1# -*- coding: utf-8 -*-
2# © Copyright EnterpriseDB UK Limited 2011-2021
3#
4# This file is part of Barman.
5#
6# Barman is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# Barman is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Barman.  If not, see <http://www.gnu.org/licenses/>.
18
19"""
20This module represents the barman diagnostic tool.
21"""
22
23import datetime
24import json
25import logging
26
27import barman
28from barman import fs, output
29from barman.backup import BackupInfo
30from barman.exceptions import CommandFailedException, FsOperationFailed
31from barman.utils import BarmanEncoder
32
33_logger = logging.getLogger(__name__)
34
35
36def exec_diagnose(servers, errors_list):
37    """
38    Diagnostic command: gathers information from backup server
39    and from all the configured servers.
40
41    Gathered information should be used for support and problems detection
42
43    :param dict(str,barman.server.Server) servers: list of configured servers
44    :param list errors_list: list of global errors
45    """
46    # global section. info about barman server
47    diagnosis = {"global": {}, "servers": {}}
48    # barman global config
49    diagnosis["global"]["config"] = dict(barman.__config__._global_config)
50    diagnosis["global"]["config"]["errors_list"] = errors_list
51    try:
52        command = fs.UnixLocalCommand()
53        # basic system info
54        diagnosis["global"]["system_info"] = command.get_system_info()
55    except CommandFailedException as e:
56        diagnosis["global"]["system_info"] = {"error": repr(e)}
57    diagnosis["global"]["system_info"]["barman_ver"] = barman.__version__
58    diagnosis["global"]["system_info"]["timestamp"] = datetime.datetime.now()
59    # per server section
60    for name in sorted(servers):
61        server = servers[name]
62        if server is None:
63            output.error("Unknown server '%s'" % name)
64            continue
65        # server configuration
66        diagnosis["servers"][name] = {}
67        diagnosis["servers"][name]["config"] = vars(server.config)
68        if "config" in diagnosis["servers"][name]["config"]:
69            del diagnosis["servers"][name]["config"]["config"]
70        # server system info
71        if server.config.ssh_command:
72            try:
73                command = fs.UnixRemoteCommand(
74                    ssh_command=server.config.ssh_command, path=server.path
75                )
76                diagnosis["servers"][name]["system_info"] = command.get_system_info()
77            except FsOperationFailed:
78                pass
79        # barman status information for the server
80        diagnosis["servers"][name]["status"] = server.get_remote_status()
81        # backup list
82        backups = server.get_available_backups(BackupInfo.STATUS_ALL)
83        diagnosis["servers"][name]["backups"] = backups
84        # wal status
85        diagnosis["servers"][name]["wals"] = {
86            "last_archived_wal_per_timeline": server.backup_manager.get_latest_archived_wals_info(),
87        }
88        # Release any PostgreSQL resource
89        server.close()
90    output.info(
91        json.dumps(diagnosis, cls=BarmanEncoder, indent=4, sort_keys=True), log=False
92    )
93