File: backend.py

package info (click to toggle)
python-haproxyadmin 0.2.4-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 436 kB
  • sloc: python: 1,500; makefile: 165; sh: 1
file content (236 lines) | stat: -rw-r--r-- 6,189 bytes parent folder | download
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# -*- coding: utf-8 -*-
#
# pylint: disable=superfluous-parens
#
"""
haproxyadmin.backend
~~~~~~~~~~~~~~~~~~~~

This module provides the :class:`Backend <.Backend>` class which allows to
run operation for a backend.

"""
from haproxyadmin.utils import (calculate, cmd_across_all_procs,
                                compare_values, converter)
from haproxyadmin.server import Server


BACKEND_METRICS = [
    'act',
    'bck',
    'bin',
    'bout',
    'chkdown',
    'cli_abrt',
    'comp_byp',
    'comp_in',
    'comp_out',
    'comp_rsp',
    'ctime',
    'downtime',
    'dreq',
    'dresp',
    'econ',
    'eresp',
    'hrsp_1xx',
    'hrsp_2xx',
    'hrsp_3xx',
    'hrsp_4xx',
    'hrsp_5xx',
    'hrsp_other',
    'lastchg',
    'lastsess',
    'lbtot',
    'qcur',
    'qmax',
    'qtime',
    'rate',
    'rate_max',
    'rtime',
    'scur',
    'slim',
    'smax',
    'srv_abrt',
    'stot',
    'ttime',
    'weight',
    'wredis',
    'wretr',
]


class Backend(object):
    """Build a user-created :class:`Backend` for a single backend.

    :param backend_per_proc: list of :class:`._Backend` objects.
    :type backend_per_proc: ``list``
    :rtype: a :class:`Backend`.
    """

    def __init__(self, backend_per_proc):
        self._backend_per_proc = backend_per_proc
        self._name = self._backend_per_proc[0].name

    # built-in comparison operator is adjusted
    def __eq__(self, other):
        if isinstance(other, Backend):
            return (self.name == other.name)
        elif isinstance(other, str):
            return (self.name == other)
        else:
            return False

    def __ne__(self, other):
        return (not self.__eq__(other))

    @property
    def iid(self):
        """Return the unique proxy ID of the backend.

        .. note::
            Because proxy ID is the same across all processes,
            we return the proxy ID from the 1st process.

        :rtype: ``int``
        """
        return int(self._backend_per_proc[0].iid)

    def servers(self, name=None):
        """Return Server object for each server.

        :param name: (optional) servername to look for. Defaults to None.
        :type name: string
        :return: A list of :class:`Server <Server>` objects
        :rtype: list
        """
        return_list = []

        # store _Server objects for each server as it is reported by each
        # process.
        # key: name of the server
        # value: a list of _Server object
        servers_across_hap_processes = {}

        # Get a list of servers (_Server objects) per process
        for backend in self._backend_per_proc:
            for server in backend.servers(name):
                if server.name not in servers_across_hap_processes:
                    servers_across_hap_processes[server.name] = []
                servers_across_hap_processes[server.name].append(server)

        # For each server build a Server object
        for server_per_proc in servers_across_hap_processes.values():
            return_list.append(Server(server_per_proc, self.name))

        return return_list

    def server(self, name):
        """Return a Server object

        :param name: Name of the server
        :type name: string
        :return: :class:`Server <Server>` object
        :rtype: haproxyadmin.Server
        """
        server = self.servers(name)
        if len(server) == 1:
            return server[0]
        elif len(server) == 0:
            raise ValueError("Could not find server")
        else:
            raise ValueError("Found more than one server, this is a bug!")

    def metric(self, name):
        """Return the value of a metric.

        Performs a calculation on the metric across all HAProxy processes.
        The type of calculation is either sum or avg and defined in
        utils.METRICS_SUM and utils.METRICS_AVG.

        :param name: Name of the metric, any of BACKEND_METRICS
        :type name: ``string``
        :return: Value of the metric after the appropriate calculation
          has been performed.
        :rtype: number, either ``integer`` or ``float``.
        :raise: ValueError when a given metric is not found.
        """
        metrics = []
        if name not in BACKEND_METRICS:
            raise ValueError("{} is not valid metric".format(name))

        metrics = [x.metric(name) for x in self._backend_per_proc]
        metrics[:] = (converter(x) for x in metrics)
        metrics[:] = (x for x in metrics if x is not None)

        return calculate(name, metrics)

    @property
    def name(self):
        """Return the name of the backend.

        :rtype: string
        """
        return self._name

    @property
    def process_nb(self):
        """Return a list of process number in which backend is configured.

        :rtype: list
        """
        process_numbers = []
        for backend in self._backend_per_proc:
            process_numbers.append(backend.process_nb)

        return process_numbers

    @property
    def requests(self):
        """Return the number of requests.

        :rtype: integer
        """
        return self.metric('stot')

    def requests_per_process(self):
        """Return the number of requests for the backend per process.

        :return: a list of tuples with 2 elements

          #. process number of HAProxy
          #. requests

        :rtype: ``list``

        """
        results = cmd_across_all_procs(self._backend_per_proc, 'metric', 'stot')

        return results

    def stats_per_process(self):
        """Return all stats of the backend per process.

        :return: a list of tuples with 2 elements

          #. process number
          #. a dict with all stats

        :rtype: ``list``

        """
        values = cmd_across_all_procs(self._backend_per_proc, 'stats')

        return values

    @property
    def status(self):
        """Return the status of the backend.

        :rtype: ``string``
        :raise: :class:`IncosistentData` exception if status is different
          per process.

        """
        results = cmd_across_all_procs(self._backend_per_proc, 'metric', 'status')

        return compare_values(results)