Merge lp:~allenap/rabbitfixture/untangle-host into lp:rabbitfixture

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: 34
Merged at revision: 30
Proposed branch: lp:~allenap/rabbitfixture/untangle-host
Merge into: lp:rabbitfixture
Diff against target: 144 lines (+48/-20)
2 files modified
rabbitfixture/server.py (+24/-15)
rabbitfixture/tests/test_server.py (+24/-5)
To merge this branch: bzr merge lp:~allenap/rabbitfixture/untangle-host
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Review via email: mp+185836@code.launchpad.net

Commit message

Fix port reuse issues when restarting the fixture.

Previously RabbitMQ was started on all addresses, the fq_hostname property was incorrectly using gethostname() regardless of the hostname given, and allocate_ports() only ever checked ports on localhost.

Description of the change

As suggested in the bug report, this branch:

- Only starts RabbitMQ on the specified address. The environment
  variable RABBITMQ_NODE_IP_ADDRESS is used to do this.

- fq_hostname uses the configured hostname.

- allocate_ports() takes a *args of addresses.

To post a comment you must log in.
Revision history for this message
Raphaël Badin (rvb) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'rabbitfixture/server.py'
2--- rabbitfixture/server.py 2012-05-15 18:09:17 +0000
3+++ rabbitfixture/server.py 2013-09-16 15:26:00 +0000
4@@ -41,21 +41,29 @@
5 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
6
7
8-def allocate_ports(n=1):
9- """Allocate `n` unused ports.
10+def get_port(socket):
11+ """Return the port to which a socket is bound."""
12+ addr, port = socket.getsockname()
13+ return port
14+
15+
16+def allocate_ports(*addrs):
17+ """Allocate `len(addrs)` unused ports.
18+
19+ A port is allocated for each element in `addrs`.
20
21 There is a small race condition here (between the time we allocate the
22 port, and the time it actually gets used), but for the purposes for which
23 this function gets used it isn't a problem in practice.
24 """
25- sockets = map(lambda _: socket.socket(), xrange(n))
26+ sockets = [socket.socket() for addr in addrs]
27 try:
28- for s in sockets:
29- s.bind(('localhost', 0))
30- return map(lambda s: s.getsockname()[1], sockets)
31+ for addr, sock in zip(addrs, sockets):
32+ sock.bind((addr, 0))
33+ return [get_port(sock) for sock in sockets]
34 finally:
35- for s in sockets:
36- s.close()
37+ for sock in sockets:
38+ sock.close()
39
40
41 # Pattern to parse rabbitctl status output to find the nodename of a running
42@@ -107,7 +115,7 @@
43 if self.hostname is None:
44 self.hostname = 'localhost'
45 if self.port is None:
46- [self.port] = allocate_ports(1)
47+ [self.port] = allocate_ports(self.hostname)
48 if self.homedir is None:
49 self.homedir = self.useFixture(TempDir()).path
50 if self.mnesiadir is None:
51@@ -121,10 +129,7 @@
52 @property
53 def fq_nodename(self):
54 """The node of the RabbitMQ that is being exported."""
55- # Note that socket.gethostname is recommended by the rabbitctl manpage
56- # even though we're always on localhost, its what the erlang cluster
57- # code wants.
58- return "%s@%s" % (self.nodename, socket.gethostname())
59+ return "%s@%s" % (self.nodename, self.hostname)
60
61
62 class RabbitServerEnvironment(Fixture):
63@@ -134,6 +139,7 @@
64
65 - ``RABBITMQ_MNESIA_BASE``
66 - ``RABBITMQ_LOG_BASE``
67+ - ``RABBITMQ_NODE_IP_ADDRESS``
68 - ``RABBITMQ_NODE_PORT``
69 - ``RABBITMQ_NODENAME``
70 - ``RABBITMQ_PLUGINS_DIR``
71@@ -156,14 +162,17 @@
72 self.useFixture(EnvironmentVariableFixture(
73 "RABBITMQ_LOG_BASE", self.config.homedir))
74 self.useFixture(EnvironmentVariableFixture(
75+ "RABBITMQ_NODE_IP_ADDRESS",
76+ socket.gethostbyname(self.config.hostname)))
77+ self.useFixture(EnvironmentVariableFixture(
78 "RABBITMQ_NODE_PORT", str(self.config.port)))
79 self.useFixture(EnvironmentVariableFixture(
80 "RABBITMQ_NODENAME", self.config.fq_nodename))
81 self.useFixture(EnvironmentVariableFixture(
82 "RABBITMQ_PLUGINS_DIR", self.config.pluginsdir))
83 self._errors = []
84- self.addDetail('rabbit-errors',
85- Content(UTF8_TEXT, self._get_errors))
86+ self.addDetail('rabbit-errors', Content(
87+ UTF8_TEXT, self._get_errors))
88
89 def _get_errors(self):
90 """Yield all errors as UTF-8 encoded text."""
91
92=== modified file 'rabbitfixture/tests/test_server.py'
93--- rabbitfixture/tests/test_server.py 2011-09-29 11:20:28 +0000
94+++ rabbitfixture/tests/test_server.py 2013-09-16 15:26:00 +0000
95@@ -7,7 +7,6 @@
96
97 import os.path
98 import socket
99-from socket import gethostname
100 from textwrap import dedent
101
102 from amqplib import client_0_8 as amqp
103@@ -15,6 +14,7 @@
104 from rabbitfixture.server import (
105 get_nodename_from_status,
106 RabbitServer,
107+ RabbitServerEnvironment,
108 RabbitServerResources,
109 )
110 from testtools import TestCase
111@@ -96,10 +96,29 @@
112 seen_homedirs.add(resources.homedir)
113
114 def test_fq_nodename(self):
115- with RabbitServerResources(nodename="nibbles") as resources:
116- self.assertEqual(
117- "nibbles@%s" % gethostname(),
118- resources.fq_nodename)
119+ resources = self.useFixture(RabbitServerResources(
120+ nodename="nibbles", hostname="127.0.0.1"))
121+ self.assertEqual("nibbles@127.0.0.1", resources.fq_nodename)
122+
123+
124+class TestRabbitServerEnvironment(TestCase):
125+
126+ def test_setup(self):
127+ config = self.useFixture(RabbitServerResources(
128+ hostname="localhost", port=1234, homedir="rabbit/homedir",
129+ mnesiadir="rabbit/mnesiadir", logfile="rabbit/logfile",
130+ nodename="rabbit-nodename"))
131+ self.useFixture(RabbitServerEnvironment(config))
132+ expected = {
133+ "RABBITMQ_MNESIA_BASE": config.mnesiadir,
134+ "RABBITMQ_LOG_BASE": config.homedir,
135+ "RABBITMQ_NODE_IP_ADDRESS": socket.gethostbyname(config.hostname),
136+ "RABBITMQ_NODE_PORT": str(config.port),
137+ "RABBITMQ_NODENAME": config.fq_nodename,
138+ "RABBITMQ_PLUGINS_DIR": config.pluginsdir,
139+ }
140+ self.assertEqual(
141+ expected, {name: os.getenv(name) for name in expected})
142
143
144 class TestFunctions(TestCase):

Subscribers

People subscribed via source and target branches

to all changes: