Skip to content

Commit bcc1c3d

Browse files
author
Pavlos Parissis
committed
Add support for changing address and port of a server
1 parent 8d1e37e commit bcc1c3d

File tree

4 files changed

+108
-21
lines changed

4 files changed

+108
-21
lines changed

haproxyadmin/command_status.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,8 @@
101101
"Can't find resolvers section.",
102102
"Can't find backend.",
103103
]
104+
105+
SUCCESS_STRING_ADDRESS = "IP changed from|no need to change the addr"
106+
SUCCESS_STRING_PORT = ("no need to change the addr, port changed from|no need "
107+
"to change the addr, no need to change the port"
108+
)

haproxyadmin/internal.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -513,18 +513,6 @@ def metric(self, name):
513513

514514
return getattr(data, name)
515515

516-
@property
517-
def address(self):
518-
"""
519-
Return server address
520-
"""
521-
data = self.stats_data()
522-
return data.addr
523-
524-
def setaddress(self, new_address):
525-
return self.command("set server {be}/{srv} addr {new_address}".format(
526-
be=self.backend.name, srv=self._name, new_address=new_address))
527-
528516
def stats(self):
529517
"""Build dictionary for all statistics reported by HAProxy.
530518

haproxyadmin/server.py

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
1212
"""
1313
from haproxyadmin.utils import (calculate, cmd_across_all_procs, compare_values,
14-
should_die, check_command, converter)
14+
should_die, check_command, converter,
15+
check_command_addr_port, elements_of_list_same)
16+
from haproxyadmin.exceptions import IncosistentData
1517

1618

1719
STATE_ENABLE = 'enable'
@@ -130,21 +132,72 @@ def check_status(self):
130132
return compare_values(values)
131133

132134
@property
133-
def address(self):
134-
return self._server_per_proc[0].address
135+
def port(self):
136+
"""Return port of server.
135137
136-
def setaddress(self, new_address):
137-
"""
138-
Set this server's address.
139138
:rtype: ``string``
140139
"""
140+
values = cmd_across_all_procs(
141+
self._server_per_proc, 'metric', 'addr'
142+
)
143+
144+
try:
145+
value = compare_values(values)
146+
except IncosistentData as exc:
147+
ports_across_proc = [value[1].split(':')[1] for value in values]
148+
if elements_of_list_same(ports_across_proc):
149+
return ports_across_proc[0]
150+
else:
151+
raise exc
152+
else:
153+
return value.split(':')[1]
154+
155+
@port.setter
156+
def port(self, port):
157+
"""Set server's port.
158+
159+
:param port: port to set.
160+
:type port: ``string``
161+
:rtype: ``bool``
162+
"""
163+
cmd = "set server {}/{} addr {} port {}".format(
164+
self.backendname, self.name, self.address, port
165+
)
166+
results = cmd_across_all_procs(self._server_per_proc, 'command', cmd)
167+
168+
return check_command_addr_port('port', results)
141169

170+
@property
171+
def address(self):
172+
"""Return address of server.
173+
174+
:rtype: ``string``
175+
"""
142176
values = cmd_across_all_procs(
143-
self._server_per_proc, 'setaddress', new_address=str(new_address)
177+
self._server_per_proc, 'metric', 'addr'
144178
)
145179

146-
return compare_values(values)
180+
try:
181+
value = compare_values(values)
182+
except IncosistentData as exc:
183+
raise exc
184+
else:
185+
return value.split(':')[0]
186+
187+
@address.setter
188+
def address(self, address):
189+
"""Set server's address.
190+
191+
:param address: address to set.
192+
:type address: ``string``
193+
:rtype: ``bool``
194+
"""
195+
cmd = "set server {}/{} addr {}".format(
196+
self.backendname, self.name, address
197+
)
198+
results = cmd_across_all_procs(self._server_per_proc, 'command', cmd)
147199

200+
return check_command_addr_port('addr', results)
148201

149202
@property
150203
def last_status(self):

haproxyadmin/utils.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
import stat
1515
from functools import wraps
1616
import six
17+
import re
1718

1819
from haproxyadmin.exceptions import (CommandFailed, MultipleCommandResults,
1920
IncosistentData)
2021
from haproxyadmin.command_status import (ERROR_OUTPUT_STRINGS,
21-
SUCCESS_OUTPUT_STRINGS)
22+
SUCCESS_OUTPUT_STRINGS, SUCCESS_STRING_PORT, SUCCESS_STRING_ADDRESS)
2223

2324
METRICS_SUM = [
2425
'CompressBpsIn',
@@ -321,6 +322,46 @@ def check_command(results):
321322
else:
322323
raise MultipleCommandResults(results)
323324

325+
def check_command_addr_port(change_type, results):
326+
"""Check if command to set port or address was successfully executed.
327+
328+
Unfortunately, haproxy returns many different combinations of output when
329+
we change the address or the port of the server and trying to determine
330+
if address or port was successfully changed isn't that trivial.
331+
332+
So, after we change address or port, we check if the same output is
333+
returned by all processes and we also check if a collection of specific
334+
strings are part of the output. This is a suboptimal solution, but I
335+
couldn't come up with something more elegant.
336+
337+
:param change_type: either ``addr`` or ``port``
338+
:type change_type: ``string``
339+
:param results: a list of tuples with 2 elements.
340+
341+
#. process number of HAProxy
342+
#. message returned by HAProxy
343+
:type results: ``list``
344+
:return: ``True`` if command was successfully executed otherwise ``False``.
345+
:rtype: ``bool``
346+
:raise: :class:`.MultipleCommandResults`, :class:`.CommandFailed` and
347+
:class:`ValueError`.
348+
"""
349+
if change_type == 'addr':
350+
_match = SUCCESS_STRING_ADDRESS
351+
elif change_type == 'port':
352+
_match = SUCCESS_STRING_PORT
353+
else:
354+
raise ValueError('invalid value for change_type')
355+
356+
if elements_of_list_same([msg[1] for msg in results]):
357+
msg = results[0][1]
358+
if re.match(_match, msg):
359+
return True
360+
else:
361+
raise CommandFailed(msg)
362+
else:
363+
raise MultipleCommandResults(results)
364+
324365

325366
def calculate(name, metrics):
326367
"""Perform the appropriate calculation across a list of metrics.

0 commit comments

Comments
 (0)