summaryrefslogtreecommitdiffstats
path: root/library/Icingadb/Command/Transport/CommandTransport.php
blob: 952cb148695b8084ef58a599889fe1b7b6a76eb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?php

/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */

namespace Icinga\Module\Icingadb\Command\Transport;

use Exception;
use Icinga\Application\Config;
use Icinga\Application\Logger;
use Icinga\Data\ConfigObject;
use Icinga\Exception\ConfigurationError;
use Icinga\Module\Icingadb\Command\IcingaCommand;

/**
 * Command transport
 */
class CommandTransport implements CommandTransportInterface
{
    /**
     * Transport configuration
     *
     * @var Config
     */
    protected static $config;

    /**
     * Get transport configuration
     *
     * @return  Config
     *
     * @throws  ConfigurationError
     */
    public static function getConfig(): Config
    {
        if (static::$config === null) {
            $config = Config::module('icingadb', 'commandtransports');
            if ($config->isEmpty()) {
                throw new ConfigurationError(
                    t('No command transports have been configured in "%s".'),
                    $config->getConfigFile()
                );
            }

            static::$config = $config;
        }

        return static::$config;
    }

    /**
     * Create a transport from config
     *
     * @param   ConfigObject<string>  $config
     *
     * @return  ApiCommandTransport
     *
     * @throws  ConfigurationError
     */
    public static function createTransport(ConfigObject $config): ApiCommandTransport
    {
        $config = clone $config;
        switch (strtolower($config->transport ?? '')) {
            case ApiCommandTransport::TRANSPORT:
                $transport = new ApiCommandTransport();
                break;
            default:
                throw new ConfigurationError(
                    t('Cannot create command transport "%s". Invalid transport defined in "%s". Use one of: %s.'),
                    $config->transport,
                    static::getConfig()->getConfigFile(),
                    join(', ', [ApiCommandTransport::TRANSPORT])
                );
        }

        unset($config->transport);
        foreach ($config as $key => $value) {
            $method = 'set' . ucfirst($key);
            if (! method_exists($transport, $method)) {
                // Ignore settings from config that don't have a setter on the transport instead of throwing an
                // exception here because the transport should throw an exception if it's not fully set up
                // when being about to send a command
                continue;
            }

            $transport->$method($value);
        }

        return $transport;
    }

    /**
     * Send the given command over an appropriate Icinga command transport
     *
     * This will try one configured transport after another until the command has been successfully sent.
     *
     * @param   IcingaCommand   $command    The command to send
     * @param   int|null        $now        Timestamp of the command or null for now
     *
     * @throws  CommandTransportException   If sending the Icinga command failed
     *
     * @return  mixed
     */
    public function send(IcingaCommand $command, int $now = null)
    {
        $errors = [];

        foreach (static::getConfig() as $name => $transportConfig) {
            $transport = static::createTransport($transportConfig);

            try {
                $result = $transport->send($command, $now);
            } catch (CommandTransportException $e) {
                Logger::error($e);
                $errors[] = sprintf('%s: %s.', $name, rtrim($e->getMessage(), '.'));
                continue; // Try the next transport
            }

            return $result; // The command was successfully sent
        }

        if (! empty($errors)) {
            throw new CommandTransportException(implode("\n", $errors));
        }

        throw new CommandTransportException(t(
            'Failed to send external Icinga command. No transport has been configured'
            . ' for this instance. Please contact your Icinga Web administrator.'
        ));
    }
}