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