Revision 58bb385c
b/daemons/import-export | ||
---|---|---|
362 | 362 |
help="X509 CA file") |
363 | 363 |
parser.add_option("--bind", dest="bind", action="store", type="string", |
364 | 364 |
help="Bind address") |
365 |
parser.add_option("--ipv4", dest="ipv4", action="store_true", |
|
366 |
help="Use IPv4 only") |
|
367 |
parser.add_option("--ipv6", dest="ipv6", action="store_true", |
|
368 |
help="Use IPv6 only") |
|
365 | 369 |
parser.add_option("--host", dest="host", action="store", type="string", |
366 | 370 |
help="Remote hostname") |
367 | 371 |
parser.add_option("--port", dest="port", action="store", type="int", |
... | ... | |
401 | 405 |
parser.error("Invalid mode: %s" % mode) |
402 | 406 |
|
403 | 407 |
# Normalize and check parameters |
404 |
if options.host is not None: |
|
408 |
if options.host is not None and not netutils.IPAddress.IsValid(options.host):
|
|
405 | 409 |
try: |
406 | 410 |
options.host = netutils.Hostname.GetNormalizedName(options.host) |
407 | 411 |
except errors.OpPrereqError, err: |
... | ... | |
423 | 427 |
parser.error("Magic must match regular expression %s" % |
424 | 428 |
constants.IE_MAGIC_RE.pattern) |
425 | 429 |
|
430 |
if options.ipv4 and options.ipv6: |
|
431 |
parser.error("Can only use one of --ipv4 and --ipv6") |
|
432 |
|
|
426 | 433 |
return (status_file_path, mode) |
427 | 434 |
|
428 | 435 |
|
b/lib/impexpd/__init__.py | ||
---|---|---|
35 | 35 |
from ganeti import constants |
36 | 36 |
from ganeti import errors |
37 | 37 |
from ganeti import utils |
38 |
from ganeti import netutils |
|
38 | 39 |
|
39 | 40 |
|
40 | 41 |
#: Used to recognize point at which socat(1) starts to listen on its socket. |
... | ... | |
144 | 145 |
if self._opts.bind is not None: |
145 | 146 |
common_addr_opts.append("bind=%s" % self._opts.bind) |
146 | 147 |
|
148 |
assert not (self._opts.ipv4 and self._opts.ipv6) |
|
149 |
|
|
150 |
if self._opts.ipv4: |
|
151 |
common_addr_opts.append("pf=ipv4") |
|
152 |
elif self._opts.ipv6: |
|
153 |
common_addr_opts.append("pf=ipv6") |
|
154 |
|
|
147 | 155 |
if self._mode == constants.IEM_IMPORT: |
148 | 156 |
if self._opts.port is None: |
149 | 157 |
port = 0 |
... | ... | |
162 | 170 |
addr2 = ["stdout"] |
163 | 171 |
|
164 | 172 |
elif self._mode == constants.IEM_EXPORT: |
173 |
if self._opts.host and netutils.IP6Address.IsValid(self._opts.host): |
|
174 |
host = "[%s]" % self._opts.host |
|
175 |
else: |
|
176 |
host = self._opts.host |
|
177 |
|
|
165 | 178 |
addr1 = ["stdin"] |
166 | 179 |
addr2 = [ |
167 |
"OPENSSL:%s:%s" % (self._opts.host, self._opts.port),
|
|
180 |
"OPENSSL:%s:%s" % (host, self._opts.port), |
|
168 | 181 |
|
169 | 182 |
# How long to wait per connection attempt |
170 | 183 |
"connect-timeout=%s" % self._opts.connect_timeout, |
... | ... | |
329 | 342 |
"""Verify address given as listening address by socat. |
330 | 343 |
|
331 | 344 |
""" |
332 |
# TODO: Implement IPv6 support |
|
333 |
if family != socket.AF_INET: |
|
345 |
if family not in (socket.AF_INET, socket.AF_INET6): |
|
334 | 346 |
raise errors.GenericError("Address family %r not supported" % family) |
335 | 347 |
|
348 |
if (family == socket.AF_INET6 and address.startswith("[") and |
|
349 |
address.endswith("]")): |
|
350 |
address = address.lstrip("[").rstrip("]") |
|
351 |
|
|
336 | 352 |
try: |
337 | 353 |
packed_address = socket.inet_pton(family, address) |
338 | 354 |
except socket.error: |
b/test/ganeti.impexpd_unittest.py | ||
---|---|---|
25 | 25 |
import sys |
26 | 26 |
import re |
27 | 27 |
import unittest |
28 |
import socket |
|
28 | 29 |
|
29 | 30 |
from ganeti import constants |
30 | 31 |
from ganeti import objects |
... | ... | |
44 | 45 |
"ca", |
45 | 46 |
"host", |
46 | 47 |
"port", |
48 |
"ipv4", |
|
49 |
"ipv6", |
|
47 | 50 |
"compress", |
48 | 51 |
"magic", |
49 | 52 |
"connect_timeout", |
... | ... | |
101 | 104 |
self.assert_(CheckCmdWord(cmd, comprcmd)) |
102 | 105 |
|
103 | 106 |
if cmd_prefix is not None: |
104 |
self.assert_(cmd_prefix in i for i in cmd)
|
|
107 |
self.assert_(compat.any(cmd_prefix in i for i in cmd))
|
|
105 | 108 |
|
106 | 109 |
if cmd_suffix is not None: |
107 |
self.assert_(cmd_suffix in i for i in cmd)
|
|
110 |
self.assert_(compat.any(cmd_suffix in i for i in cmd))
|
|
108 | 111 |
|
109 | 112 |
# Check socat command |
110 | 113 |
socat_cmd = builder._GetSocatCommand() |
... | ... | |
118 | 121 |
|
119 | 122 |
self.assert_("verify=1" in ssl_addr) |
120 | 123 |
|
124 |
def testIPv6(self): |
|
125 |
for mode in [constants.IEM_IMPORT, constants.IEM_EXPORT]: |
|
126 |
opts = CmdBuilderConfig(host="localhost", port=6789, |
|
127 |
ipv4=False, ipv6=False) |
|
128 |
builder = impexpd.CommandBuilder(mode, opts, 1, 2, 3) |
|
129 |
cmd = builder._GetSocatCommand() |
|
130 |
self.assert_(compat.all("pf=" not in i for i in cmd)) |
|
131 |
|
|
132 |
# IPv4 |
|
133 |
opts = CmdBuilderConfig(host="localhost", port=6789, |
|
134 |
ipv4=True, ipv6=False) |
|
135 |
builder = impexpd.CommandBuilder(mode, opts, 1, 2, 3) |
|
136 |
cmd = builder._GetSocatCommand() |
|
137 |
self.assert_(compat.any(",pf=ipv4" in i for i in cmd)) |
|
138 |
|
|
139 |
# IPv6 |
|
140 |
opts = CmdBuilderConfig(host="localhost", port=6789, |
|
141 |
ipv4=False, ipv6=True) |
|
142 |
builder = impexpd.CommandBuilder(mode, opts, 1, 2, 3) |
|
143 |
cmd = builder._GetSocatCommand() |
|
144 |
self.assert_(compat.any(",pf=ipv6" in i for i in cmd)) |
|
145 |
|
|
146 |
# IPv4 and IPv6 |
|
147 |
opts = CmdBuilderConfig(host="localhost", port=6789, |
|
148 |
ipv4=True, ipv6=True) |
|
149 |
builder = impexpd.CommandBuilder(mode, opts, 1, 2, 3) |
|
150 |
self.assertRaises(AssertionError, builder._GetSocatCommand) |
|
151 |
|
|
121 | 152 |
def testCommaError(self): |
122 | 153 |
opts = CmdBuilderConfig(host="localhost", port=1234, |
123 | 154 |
ca="/some/path/with,a/,comma") |
... | ... | |
155 | 186 |
self.assertRaises(errors.GenericError, builder.GetCommand) |
156 | 187 |
|
157 | 188 |
|
189 |
class TestVerifyListening(unittest.TestCase): |
|
190 |
def test(self): |
|
191 |
self.assertEqual(impexpd._VerifyListening(socket.AF_INET, |
|
192 |
"192.0.2.7", 1234), |
|
193 |
("192.0.2.7", 1234)) |
|
194 |
self.assertEqual(impexpd._VerifyListening(socket.AF_INET6, "::1", 9876), |
|
195 |
("::1", 9876)) |
|
196 |
self.assertEqual(impexpd._VerifyListening(socket.AF_INET6, "[::1]", 4563), |
|
197 |
("::1", 4563)) |
|
198 |
self.assertEqual(impexpd._VerifyListening(socket.AF_INET6, |
|
199 |
"[2001:db8::1:4563]", 4563), |
|
200 |
("2001:db8::1:4563", 4563)) |
|
201 |
|
|
202 |
def testError(self): |
|
203 |
for family in [socket.AF_UNIX, socket.AF_INET, socket.AF_INET6]: |
|
204 |
self.assertRaises(errors.GenericError, impexpd._VerifyListening, |
|
205 |
family, "", 1234) |
|
206 |
self.assertRaises(errors.GenericError, impexpd._VerifyListening, |
|
207 |
family, "192", 999) |
|
208 |
|
|
209 |
for family in [socket.AF_UNIX, socket.AF_INET6]: |
|
210 |
self.assertRaises(errors.GenericError, impexpd._VerifyListening, |
|
211 |
family, "192.0.2.7", 1234) |
|
212 |
self.assertRaises(errors.GenericError, impexpd._VerifyListening, |
|
213 |
family, "[2001:db8::1", 1234) |
|
214 |
self.assertRaises(errors.GenericError, impexpd._VerifyListening, |
|
215 |
family, "2001:db8::1]", 1234) |
|
216 |
|
|
217 |
for family in [socket.AF_UNIX, socket.AF_INET]: |
|
218 |
self.assertRaises(errors.GenericError, impexpd._VerifyListening, |
|
219 |
family, "::1", 1234) |
|
220 |
|
|
221 |
|
|
158 | 222 |
class TestCalcThroughput(unittest.TestCase): |
159 | 223 |
def test(self): |
160 | 224 |
self.assertEqual(impexpd._CalcThroughput([]), None) |
Also available in: Unified diff