Commit 11806dbc authored by Marco Nenciarini's avatar Marco Nenciarini

New upstream version 2.8

parent da669815
2019-05-14 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Update the ChangeLog file
Update NEWS file for release 2.8
Version set to 2.8
2019-05-10 Gabriele Bartolini <gabriele.bartolini@2ndQuadrant.it>
Improve documentation on backup from standby
From now on support only PostgreSQL 9.4+ and recommend
just WAL streaming (with replication slots) from the standby
as WAL shipping method.
2019-05-13 Gabriele Bartolini <gabriele.bartolini@2ndQuadrant.it>
Updated requirements section in the documentation
Python 3 becomes officially supported. 2.6 and 2.7 are deprecated.
Marked pre-9.4 versions of PostgreSQL deprecated.
2019-05-14 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Add '--test' option to barman-wal-archive and barman-wal-restore
2019-05-13 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Add a warning on empty backup_option with rsync_backup method
2019-05-12 Gabriele Bartolini <gabriele.bartolini@2ndQuadrant.it>
Cosmetic changes in default barman.conf
2019-05-10 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Do not report logical decoding connection is replication-status
Report remote command in logs during recovery
Clarify check --nagios output about inactive servers
Fix issues found by flake8 running on Python 3.x
2019-05-09 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Incremental backup copy in passive nodes
Add support for `reuse_backup` in geo-redundancy
2019-05-08 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Support for double quotes in 'synchronous_standby_names' setting
2019-05-07 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Fix sync-wals error if primary has WALs older than the first backup
2019-04-30 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Update Sphinx docuemntation build environment
2019-04-15 Giulio Calacoci <giulio.calacoci@2ndquadrant.it>
Merge barman-cli code with barman
We are in the process or reorganising the barman codebase.
During this stage the code from barman-cli is going to be included in
the barman codebase and distributed with the barman package.
2019-04-26 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Avoid using dateutil.parser in copy_controller
Parsing the date with dateutil.parser is too slow to be used with
millions of files. We know the format of the date we are going to
parse so we can replace it with a couple of strptime calls.
Closes: GH-210
2019-04-12 Jeff Janes <jeff.janes@gmail.com>
Remove spurious message when resetting WAL
When calling "barman receive-wal --reset foo", it gives
a message:
Starting receive-wal for server foo
However, it does not actually attempt to start the receive-wal
process when called with --reset.
Closes: GH-215
2019-04-13 Jeff Janes <jeff.janes@gmail.com>
Fix exclude_and_protect_filter
Filters which do not start with '/' are treated as wildcards.
For the exclude_and_protect_filter, this is both slow and
incorrect. For example, if there were a spurious file named
"pg_xact/0000" somewhere other than the top-level dest data
directory, the unachored protect filter means it would not
get deleted. With an anchored protect filter, it will get
deleted, as it should.
So fix this by prefixing the filter paths with a '/'.
The bug fix is minor (it is not clear why such spurious files
would exist in the first place) but the speed-up should be
appreciated by anyone with a large number of files in their
database.
Closes: GH-217
2019-04-24 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Fix encoding error in get-wal on Python 3
Make sure that WAL files are read and written as bytes.
Closes: GH-221
Fix TypeError exception running sync-info --primary with Python 3
In Python 2, additional positional arguments passed to json.dumps
are silently discarded. Python 3 is stricter and highlighted an
unused positional argument in a json.dumps call. The argument has
been removed.
2019-04-17 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Make sure barman configuration does not use a strict ConfigParser
In Python 3 ConfigParser has changed to be strict by default.
Barman wants to preserve the Python 2 behavior, so we are explicitly
building it passing strict=False.
2019-04-16 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Add Python 3.7 to unit tests
2019-04-15 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Support psycopg2 2.8 in unit tests
2019-04-02 Gabriele Bartolini <gabriele.bartolini@2ndQuadrant.it>
Collect more PostgreSQL settings during get_remote_status()
Added settings are:
* archive_timeout
* data_checksums
* hot_standby
* max_wal_senders
* max_replication_slots
* wal_compression
Display the above settings in the `show-server` and `diagnose` commands
2019-03-20 Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Version set to 2.8a1
Update the ChangeLog file
Update NEWS file for release 2.7
......
Barman News - History of user-visible changes
Copyright (C) 2011-2019 2ndQuadrant Limited
Version 2.8 - 17 May 2019
- Add support for reuse_backup in geo-redundancy for incremental
backup copy in passive nodes
- Improve performance of rsync based copy by using strptime instead of
the more generic dateutil.parser (#210)
- Add ‘–test’ option to barman-wal-archive and barman-wal-restore to
verify the connection with the Barman server
- Complain if backup_options is not explicitly set, as the future
default value will change from exclusive_backup to concurrent_backup
when PostgreSQL 9.5 will be declared EOL by the PGDG
- Display additional settings in the show-server and diagnose
commands: archive_timeout, data_checksums, hot_standby,
max_wal_senders, max_replication_slots and wal_compression.
- Merge the barman-cli project in Barman
- Bug fixes:
- Fix encoding error in get-wal on Python 3 (Jeff Janes, #221)
- Fix exclude_and_protect_filter (Jeff Janes, #217)
- Remove spurious message when resetting WAL (Jeff Janes, #215)
- Fix sync-wals error if primary has WALs older than the first
backup
- Support for double quotes in synchronous_standby_names setting
- Minor changes:
- Improve messaging of check --nagios for inactive servers
- Log remote SSH command with recover command
- Hide logical decoding connections in replication-status command
This release officially supports Python 3 and deprecates Python 2 (which
might be discontinued in future releases).
PostgreSQL 9.3 and older is deprecated from this release of Barman.
Support for backup from standby is now limited to PostgreSQL 9.4 or
higher and to WAL shipping from the standby (please refer to the
documentation for details).
Version 2.7 - 21 Mar 2019
- Fix error handling during the parallel backup. Previously an
......
Metadata-Version: 1.1
Name: barman
Version: 2.7
Version: 2.8
Summary: Backup and Recovery Manager for PostgreSQL
Home-page: http://www.pgbarman.org/
Author: 2ndQuadrant Limited
......
......@@ -24,7 +24,6 @@ Barman:
- TODO : our wishlist for Barman
- barman : sources in Python
- doc : tutorial and man pages
- rpm : SPEC files for RHEL distributions
- scripts : auxiliary scripts
- tests : unit tests
......@@ -38,7 +37,6 @@ Web resources
- Man page, section 5 : http://docs.pgbarman.org/barman.5.html
- Community support : http://www.pgbarman.org/support/
- Professional support : https://www.2ndquadrant.com/
- Client utilities : https://github.com/2ndquadrant-it/barman-cli
- pgespresso extension : https://github.com/2ndquadrant-it/pgespresso
Licence
......
Metadata-Version: 1.1
Name: barman
Version: 2.7
Version: 2.8
Summary: Backup and Recovery Manager for PostgreSQL
Home-page: http://www.pgbarman.org/
Author: 2ndQuadrant Limited
......
......@@ -35,11 +35,18 @@ barman/xlog.py
barman.egg-info/PKG-INFO
barman.egg-info/SOURCES.txt
barman.egg-info/dependency_links.txt
barman.egg-info/entry_points.txt
barman.egg-info/requires.txt
barman.egg-info/top_level.txt
bin/barman
barman/clients/__init__.py
barman/clients/walarchive.py
barman/clients/walrestore.py
doc/.gitignore
doc/Makefile
doc/barman-wal-archive.1
doc/barman-wal-archive.1.md
doc/barman-wal-restore.1
doc/barman-wal-restore.1.md
doc/barman.1
doc/barman.5
doc/barman.conf
......
[console_scripts]
barman = barman.cli:main
barman-wal-archive = barman.clients.walarchive:main
barman-wal-restore = barman.clients.walrestore:main
psycopg2>=2.4.2
argh<=0.26.2,>=0.21.2
python-dateutil<2.7.0
argh>=0.21.2
python-dateutil
argcomplete
......@@ -668,9 +668,14 @@ class SshBackupExecutor(with_metaclass(ABCMeta, BackupExecutor)):
BackupOptions.EXCLUSIVE_BACKUP in backup_options)
if not concurrent_backup and not exclusive_backup:
self.config.backup_options.add(BackupOptions.EXCLUSIVE_BACKUP)
output.debug("The default backup strategy for "
"any ssh based backup_method is: "
"exclusive_backup")
output.warning(
"No backup strategy set for server '%s' "
"(using default 'exclusive_backup').",
self.config.name)
output.warning(
"The default backup strategy will change "
"to 'concurrent_backup' in the future. "
"Explicitly set 'backup_options' to silence this warning.")
# Depending on the backup options value, create the proper strategy
if BackupOptions.CONCURRENT_BACKUP in self.config.backup_options:
......
......@@ -687,8 +687,7 @@ def sync_info(args):
if getattr(args, 'primary', False):
primary_info = server.primary_node_info(args.last_wal,
args.last_position)
output.info(json.dumps(primary_info, sys.stdout,
cls=BarmanEncoder, indent=4),
output.info(json.dumps(primary_info, cls=BarmanEncoder, indent=4),
log=False)
else:
server.sync_status(args.last_wal, args.last_position)
......@@ -843,6 +842,12 @@ def delete(args):
metavar='SIZE',
type=check_positive,
default=SUPPRESS)
@arg('--test', '-t',
help="test both the connection and the configuration of the requested "
"PostgreSQL server in Barman for WAL retrieval. With this option, "
"the 'wal_name' mandatory argument is ignored.",
action='store_true',
default=SUPPRESS)
@expects_obj
def get_wal(args):
"""
......@@ -852,6 +857,11 @@ def get_wal(args):
"""
server = get_server(args, inactive_is_error=True)
if getattr(args, 'test', None):
output.info("Ready to retrieve WAL files from the server %s",
server.config.name)
return
# Retrieve optional arguments. If an argument is not specified,
# the namespace doesn't contain it due to SUPPRESS default.
# In that case we pick 'None' using getattr third argument.
......@@ -871,6 +881,12 @@ def get_wal(args):
@arg('server_name',
completer=server_completer,
help='specifies the server name for the command')
@arg('--test', '-t',
help='test both the connection and the configuration of the requested '
'PostgreSQL server in Barman to make sure it is ready to receive '
'WAL files.',
action='store_true',
default=SUPPRESS)
@expects_obj
def put_wal(args):
"""
......@@ -878,6 +894,12 @@ def put_wal(args):
directory. The file will be read from standard input in tar format.
"""
server = get_server(args, inactive_is_error=True)
if getattr(args, 'test', None):
output.info("Ready to accept WAL files for the server %s",
server.config.name)
return
try:
# Python 3.x
stream = sys.stdin.buffer
......@@ -1068,7 +1090,7 @@ def get_server(args, skip_inactive=True, skip_disabled=False,
:param bool inactive_is_error: treat inactive server as error
:param bool on_error_stop: stop if an error is found
:param bool suppress_error: suppress display of errors (e.g. diagnose)
:rtype: barman.server.Server|None
:rtype: Server|None
"""
# This function must to be called with in a single-server context
name = args.server_name
......
#!/usr/bin/env python
#
# Copyright (C) 2011-2018 2ndQuadrant Limited
# Copyright (C) 2019 2ndQuadrant Limited
#
# This file is part of Barman.
#
......@@ -16,12 +14,3 @@
#
# You should have received a copy of the GNU General Public License
# along with Barman. If not, see <http://www.gnu.org/licenses/>.
#
# PYTHON_ARGCOMPLETE_OK
from barman.cli import main
if __name__ == '__main__':
main()
else:
raise NotImplementedError
This diff is collapsed.
This diff is collapsed.
......@@ -573,7 +573,15 @@ class Config(object):
_QUOTE_RE = re.compile(r"""^(["'])(.*)\1$""")
def __init__(self, filename=None):
self._config = ConfigParser()
# In Python 3 ConfigParser has changed to be strict by default.
# Barman wants to preserve the Python 2 behavior, so we are
# explicitly building it passing strict=False.
try:
# Python 3.x
self._config = ConfigParser(strict=False)
except TypeError:
# Python 2.x
self._config = ConfigParser()
if filename:
if hasattr(filename, 'read'):
self._config.readfp(filename)
......
......@@ -33,7 +33,6 @@ import tempfile
from functools import partial
from multiprocessing import Lock, Pool
import dateutil.parser
import dateutil.tz
from barman.command_wrappers import RsyncPgData
......@@ -851,8 +850,8 @@ class RsyncCopyController(object):
# Add every file in the source path to the list of files
# to be protected from deletion ('exclude_and_protect.filter')
exclude_and_protect_filter.write('P ' + entry.path + '\n')
exclude_and_protect_filter.write('- ' + entry.path + '\n')
exclude_and_protect_filter.write('P /' + entry.path + '\n')
exclude_and_protect_filter.write('- /' + entry.path + '\n')
# If source item is older than safe_horizon,
# add it to 'safe.list'
......@@ -945,6 +944,8 @@ class RsyncCopyController(object):
# Ref: http://ftp.samba.org/pub/rsync/src/rsync-3.1.0-NEWS
rsync.get_output('--no-human-readable', '--list-only', '-r', path,
check=True)
# Cache tzlocal object we need to build dates
tzinfo = dateutil.tz.tzlocal()
for line in rsync.out.splitlines():
line = line.rstrip()
match = self.LIST_ONLY_RE.match(line)
......@@ -953,8 +954,18 @@ class RsyncCopyController(object):
# no exceptions here: the regexp forces 'size' to be an integer
size = int(match.group('size'))
try:
date = dateutil.parser.parse(match.group('date'))
date = date.replace(tzinfo=dateutil.tz.tzlocal())
date_str = match.group('date')
# The date format has been validated by LIST_ONLY_RE.
# Use "2014/06/05 18:00:00" format if the sending rsync
# is compiled with HAVE_STRFTIME, otherwise use
# "Thu Jun 5 18:00:00 2014" format
if date_str[0].isdigit():
date = datetime.datetime.strptime(
date_str, "%Y/%m/%d %H:%M:%S")
else:
date = datetime.datetime.strptime(
date_str, "%a %b %d %H:%M:%S %Y")
date = date.replace(tzinfo=tzinfo)
except (TypeError, ValueError):
# This should not happen, due to the regexp
msg = ("Unable to parse rsync --list-only output line "
......
......@@ -1038,7 +1038,7 @@ class NagiosOutputWriter(ConsoleOutputWriter):
error_exit_code = 2
return
if len(issues) > 0:
if len(issues) > 0 and error_occurred:
fail_summary = []
details = []
for server in issues:
......@@ -1083,10 +1083,31 @@ class NagiosOutputWriter(ConsoleOutputWriter):
for issue in details:
print(issue)
error_exit_code = 2
elif len(issues) > 0 and not error_occurred:
# Some issues, but only in skipped server
good = [item for item in servers if item not in issues]
# Display the output message for a single server check
if len(good) == 0:
print("BARMAN OK - No server configured * IGNORING: %s" %
(" * IGNORING: ".join(issues)))
elif len(good) == 1:
print("BARMAN OK - Ready to serve the Espresso backup "
"for %s * IGNORING: %s" %
(good[0], " * IGNORING: ".join(issues)))
else:
# Display the output message for several servers, using
# '*' as delimiter
print("BARMAN OK - Ready to serve the Espresso backup "
"for %d servers * %s * IGNORING: %s" % (
len(good),
" * ".join(good),
" * IGNORING: ".join(issues)))
else:
# No issues, all good!
# Display the output message for a single server check
if len(servers) == 1:
if not len(servers):
print("BARMAN OK - No server configured")
elif len(servers) == 1:
print("BARMAN OK - Ready to serve the Espresso backup "
"for %s" %
(servers[0]))
......@@ -1094,9 +1115,8 @@ class NagiosOutputWriter(ConsoleOutputWriter):
# Display the output message for several servers, using
# '*' as delimiter
print("BARMAN OK - Ready to serve the Espresso backup "
"for %d server(s) * %s" % (
len(servers),
" * ".join([server for server in servers])))
"for %d servers * %s" % (
len(servers), " * ".join(servers)))
#: This dictionary acts as a registry of available OutputWriters
......
......@@ -635,6 +635,30 @@ class PostgreSQLConnection(PostgreSQL):
force_str(e).strip())
return None
@property
def archive_timeout(self):
"""
Retrieve the archive_timeout setting in PostgreSQL
:return: The archive timeout (in seconds)
"""
try:
cur = self._cursor(cursor_factory=DictCursor)
# We can't use the `get_setting` method here, because it
# uses `SHOW`, returning an human readable value such as "5min",
# while we prefer a raw value such as 300.
cur.execute("SELECT setting "
"FROM pg_settings "
"WHERE name='archive_timeout'")
result = cur.fetchone()
archive_timeout = int(result[0])
return archive_timeout
except ValueError as e:
_logger.error("Error retrieving archive_timeout: %s",
force_str(e).strip())
return None
def get_archiver_stats(self):
"""
This method gathers statistics from pg_stat_archiver.
......@@ -705,9 +729,21 @@ class PostgreSQLConnection(PostgreSQL):
pg_superuser_settings + pg_settings + pg_query_keys,
None)
try:
# check for wal_level only if the version is >= 9.0
# Retrieve wal_level, hot_standby and max_wal_senders
# only if version is >= 9.0
if self.server_version >= 90000:
pg_settings.append('wal_level')
pg_settings.append('hot_standby')
pg_settings.append('max_wal_senders')
if self.server_version >= 90300:
pg_settings.append('data_checksums')
if self.server_version >= 90400:
pg_settings.append('max_replication_slots')
if self.server_version >= 90500:
pg_settings.append('wal_compression')
# retrieves superuser settings
if self.is_superuser:
......@@ -724,6 +760,7 @@ class PostgreSQLConnection(PostgreSQL):
result['pgespresso_installed'] = self.has_pgespresso
result['current_xlog'] = self.current_xlog_file_name
result['current_size'] = self.current_size
result['archive_timeout'] = self.archive_timeout
result.update(self.get_configuration_files())
......@@ -1209,12 +1246,14 @@ class PostgreSQLConnection(PostgreSQL):
raise PostgresUnsupportedFeature('9.1')
from_repslot = ""
where_clauses = []
if self.server_version >= 100000:
# Current implementation (10+)
what = "r.*, rs.slot_name"
# Look for replication slot name
from_repslot = "LEFT JOIN pg_replication_slots rs " \
"ON (r.pid = rs.active_pid) "
where_clauses += ["rs.slot_type = 'physical'"]
elif self.server_version >= 90500:
# PostgreSQL 9.5/9.6
what = "pid, " \
......@@ -1237,6 +1276,7 @@ class PostgreSQLConnection(PostgreSQL):
# Look for replication slot name
from_repslot = "LEFT JOIN pg_replication_slots rs " \
"ON (r.pid = rs.active_pid) "
where_clauses += ["rs.slot_type = 'physical'"]
elif self.server_version >= 90400:
# PostgreSQL 9.4
what = "pid, " \
......@@ -1295,12 +1335,15 @@ class PostgreSQLConnection(PostgreSQL):
# Streaming client
if client_type == self.STANDBY:
# Standby server
where = 'WHERE {replay_lsn} IS NOT NULL '.format(
**self.name_map)
where_clauses += ['{replay_lsn} IS NOT NULL'.format(
**self.name_map)]
elif client_type == self.WALSTREAMER:
# WAL streamer
where = 'WHERE {replay_lsn} IS NULL '.format(
**self.name_map)
where_clauses += ['{replay_lsn} IS NULL'.format(
**self.name_map)]
if where_clauses:
where = 'WHERE %s ' % ' AND '.join(where_clauses)
else:
where = ''
......@@ -1389,7 +1432,9 @@ class PostgreSQLConnection(PostgreSQL):
if names_end < 0:
names_end = len(synchronous_standby_names)
names_list = synchronous_standby_names[names_start:names_end]
return [x.strip() for x in names_list.split(',')]
# We can blindly strip double quotes because PostgreSQL enforces
# the format of the synchronous_standby_names content
return [x.strip().strip('"') for x in names_list.split(',')]
@property
def name_map(self):
......
......@@ -123,6 +123,8 @@ class RecoveryExecutor(object):
recovery_info['recovery_dest'], self.server.config.name,
backup_info.backup_id)
output.info("Destination directory: %s", dest)
if remote_command:
output.info("Remote command: %s", remote_command)
# If the backup we are recovering is still not validated and we
# haven't requested the get-wal feature, display a warning message
......
......@@ -1067,6 +1067,13 @@ class Server(RemoteStatusMixin):
# Invoke sanity check of the backup
if backup_info.status == BackupInfo.WAITING_FOR_WALS:
self.check_backup(backup_info)
# At this point is safe to remove any remaining WAL file before the
# first backup
previous_backup = self.get_previous_backup(backup_info.backup_id)
if not previous_backup:
self.backup_manager.remove_wal_before_backup(backup_info)
except LockFileBusy:
output.error("Another backup process is running")
......@@ -1450,7 +1457,7 @@ class Server(RemoteStatusMixin):
if output_directory is not None:
destination_path = os.path.join(output_directory, wal_name)
try:
destination = open(destination_path, 'w')
destination = open(destination_path, 'wb')
output.info(
"Writing WAL '%s' for server '%s' into '%s' file%s",
wal_name, self.config.name, destination_path,
......@@ -1460,7 +1467,12 @@ class Server(RemoteStatusMixin):
destination_path, source_suffix, e)
return
else:
destination = sys.stdout
try:
# Python 3.x
destination = sys.stdout.buffer
except AttributeError:
# Python 2.x
destination = sys.stdout
_logger.info(
"Writing WAL '%s' for server '%s' to standard output%s",
wal_name, self.config.name, source_suffix)
......@@ -1509,7 +1521,7 @@ class Server(RemoteStatusMixin):
source_file = compressed_file.name
# Copy the prepared source file to destination
with open(source_file) as input_file:
with open(source_file, 'rb') as input_file:
shutil.copyfileobj(input_file, destination)
# Remove temp files
......@@ -1929,7 +1941,7 @@ class Server(RemoteStatusMixin):
except PostgresInvalidReplicationSlot:
output.error("Replication slot '%s' does not exist",
self.config.slot_name)
except PostgresReplicationSlotInUse as exc:
except PostgresReplicationSlotInUse:
output.error(
"Cannot drop replication slot '%s' on server '%s' "
"because it is in use.",
......@@ -1960,7 +1972,9 @@ class Server(RemoteStatusMixin):
"barman configuration file")
return
output.info("Starting receive-wal for server %s", self.config.name)
if not reset:
output.info("Starting receive-wal for server %s", self.config.name)
try:
# Take care of the receive-wal lock.
# Only one receiving process per server is permitted
......@@ -2421,6 +2435,11 @@ class Server(RemoteStatusMixin):
# get_available_backups method
# (BackupInfo.DONE)
backups = self.get_available_backups()
# Retrieve the first wal associated to a backup, it will be useful
# to filter our eventual WAL too old to be useful
first_useful_wal = None
if backups:
first_useful_wal = backups[sorted(backups.keys())[0]].begin_wal
# Read xlogdb file.
with self.xlogdb() as fxlogdb:
starting_point = self.set_sync_starting_point(fxlogdb,
......@@ -2445,7 +2464,11 @@ class Server(RemoteStatusMixin):
else:
check_first_wal = False
# If last_wal is provided, discard any line older than last_wal
if last_wal is not None and wal_info.name <= last_wal:
if last_wal:
if wal_info.name <= last_wal:
continue
# Else don't return any WAL older than first available backup
elif first_useful_wal and wal_info.name < first_useful_wal:
continue
wals.append(wal_info)
if wal_info is not None:
......@@ -2598,12 +2621,14 @@ class Server(RemoteStatusMixin):
Check if it is necessary to sync a backup.
If the backup is present on the Primary node:
* if it does not exist locally: continue (synchronise it)
* if it exists and is DONE locally: raise SyncNothingToDo
(nothing to do)
* if it exists and is FAILED locally: continue (try to recover it)
If the backup is not present on the Primary node:
* if it does not exist locally: raise SyncError (wrong call)
* if it exists and is DONE locally: raise SyncNothingToDo
(nothing to do)
......@@ -2855,6 +2880,8 @@ class Server(RemoteStatusMixin):
with ServerBackupSyncLock(self.config.barman_lock_directory,
self.config.name, backup_name):
try:
backup_manager = self.backup_manager
# Build a BackupInfo object
local_backup_info = BackupInfo.from_json(
self,
......@@ -2862,7 +2889,31 @@ class Server(RemoteStatusMixin):
local_backup_info.set_attribute('status',
BackupInfo.SYNCING)
local_backup_info.save()
self.backup_manager.backup_cache_add(local_backup_info)
backup_manager.backup_cache_add(local_backup_info)