diff --git a/swift/common/utils/__init__.py b/swift/common/utils/__init__.py
index 200fff1db2..7e4ffda80b 100644
--- a/swift/common/utils/__init__.py
+++ b/swift/common/utils/__init__.py
@@ -65,7 +65,6 @@ from eventlet.event import Event
from eventlet.green import socket, threading
import eventlet.hubs
import eventlet.queue
-import netifaces
import codecs
utf8_decoder = codecs.getdecoder('utf-8')
utf8_encoder = codecs.getencoder('utf-8')
@@ -118,7 +117,14 @@ from swift.common.utils.timestamp import ( # noqa
last_modified_date_to_timestamp,
normalize_delete_at_timestamp,
)
-
+from swift.common.utils.ipaddrs import ( # noqa
+ is_valid_ip,
+ is_valid_ipv4,
+ is_valid_ipv6,
+ expand_ipv6,
+ parse_socket_string,
+ whataremyips,
+)
from logging.handlers import SysLogHandler
import logging
@@ -134,9 +140,6 @@ SWIFT_CONF_FILE = '/etc/swift/swift.conf'
O_TMPFILE = getattr(os, 'O_TMPFILE', 0o20000000 | os.O_DIRECTORY)
-# Used by the parse_socket_string() function to validate IPv6 addresses
-IPV6_RE = re.compile(r"^\[(?P
.*)\](:(?P[0-9]+))?$")
-
MD5_OF_EMPTY_STRING = 'd41d8cd98f00b204e9800998ecf8427e'
RESERVED_BYTE = b'\x00'
RESERVED_STR = u'\x00'
@@ -2051,125 +2054,6 @@ def parse_options(parser=None, once=False, test_args=None):
return config, options
-def is_valid_ip(ip):
- """
- Return True if the provided ip is a valid IP-address
- """
- return is_valid_ipv4(ip) or is_valid_ipv6(ip)
-
-
-def is_valid_ipv4(ip):
- """
- Return True if the provided ip is a valid IPv4-address
- """
- try:
- socket.inet_pton(socket.AF_INET, ip)
- except socket.error: # not a valid IPv4 address
- return False
- return True
-
-
-def is_valid_ipv6(ip):
- """
- Returns True if the provided ip is a valid IPv6-address
- """
- try:
- socket.inet_pton(socket.AF_INET6, ip)
- except socket.error: # not a valid IPv6 address
- return False
- return True
-
-
-def expand_ipv6(address):
- """
- Expand ipv6 address.
- :param address: a string indicating valid ipv6 address
- :returns: a string indicating fully expanded ipv6 address
-
- """
- packed_ip = socket.inet_pton(socket.AF_INET6, address)
- return socket.inet_ntop(socket.AF_INET6, packed_ip)
-
-
-def whataremyips(ring_ip=None):
- """
- Get "our" IP addresses ("us" being the set of services configured by
- one `*.conf` file). If our REST listens on a specific address, return it.
- Otherwise, if listen on '0.0.0.0' or '::' return all addresses, including
- the loopback.
-
- :param str ring_ip: Optional ring_ip/bind_ip from a config file; may be
- IP address or hostname.
- :returns: list of Strings of ip addresses
- """
- if ring_ip:
- # See if bind_ip is '0.0.0.0'/'::'
- try:
- _, _, _, _, sockaddr = socket.getaddrinfo(
- ring_ip, None, 0, socket.SOCK_STREAM, 0,
- socket.AI_NUMERICHOST)[0]
- if sockaddr[0] not in ('0.0.0.0', '::'):
- return [ring_ip]
- except socket.gaierror:
- pass
-
- addresses = []
- for interface in netifaces.interfaces():
- try:
- iface_data = netifaces.ifaddresses(interface)
- for family in iface_data:
- if family not in (netifaces.AF_INET, netifaces.AF_INET6):
- continue
- for address in iface_data[family]:
- addr = address['addr']
-
- # If we have an ipv6 address remove the
- # %ether_interface at the end
- if family == netifaces.AF_INET6:
- addr = expand_ipv6(addr.split('%')[0])
- addresses.append(addr)
- except ValueError:
- pass
- return addresses
-
-
-def parse_socket_string(socket_string, default_port):
- """
- Given a string representing a socket, returns a tuple of (host, port).
- Valid strings are DNS names, IPv4 addresses, or IPv6 addresses, with an
- optional port. If an IPv6 address is specified it **must** be enclosed in
- [], like *[::1]* or *[::1]:11211*. This follows the accepted prescription
- for `IPv6 host literals`_.
-
- Examples::
-
- server.org
- server.org:1337
- 127.0.0.1:1337
- [::1]:1337
- [::1]
-
- .. _IPv6 host literals: https://tools.ietf.org/html/rfc3986#section-3.2.2
- """
- port = default_port
- # IPv6 addresses must be between '[]'
- if socket_string.startswith('['):
- match = IPV6_RE.match(socket_string)
- if not match:
- raise ValueError("Invalid IPv6 address: %s" % socket_string)
- host = match.group('address')
- port = match.group('port') or port
- else:
- if ':' in socket_string:
- tokens = socket_string.split(':')
- if len(tokens) > 2:
- raise ValueError("IPv6 addresses must be between '[]'")
- host, port = tokens
- else:
- host = socket_string
- return (host, port)
-
-
def select_ip_port(node_dict, use_replication=False):
"""
Get the ip address and port that should be used for the given
diff --git a/swift/common/utils/ipaddrs.py b/swift/common/utils/ipaddrs.py
new file mode 100644
index 0000000000..8375a0a1f4
--- /dev/null
+++ b/swift/common/utils/ipaddrs.py
@@ -0,0 +1,141 @@
+# Copyright (c) 2010-2012 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import netifaces
+import re
+import socket
+
+
+# Used by the parse_socket_string() function to validate IPv6 addresses
+IPV6_RE = re.compile(r"^\[(?P.*)\](:(?P[0-9]+))?$")
+
+
+def is_valid_ip(ip):
+ """
+ Return True if the provided ip is a valid IP-address
+ """
+ return is_valid_ipv4(ip) or is_valid_ipv6(ip)
+
+
+def is_valid_ipv4(ip):
+ """
+ Return True if the provided ip is a valid IPv4-address
+ """
+ try:
+ socket.inet_pton(socket.AF_INET, ip)
+ except socket.error: # not a valid IPv4 address
+ return False
+ return True
+
+
+def is_valid_ipv6(ip):
+ """
+ Returns True if the provided ip is a valid IPv6-address
+ """
+ try:
+ socket.inet_pton(socket.AF_INET6, ip)
+ except socket.error: # not a valid IPv6 address
+ return False
+ return True
+
+
+def expand_ipv6(address):
+ """
+ Expand ipv6 address.
+ :param address: a string indicating valid ipv6 address
+ :returns: a string indicating fully expanded ipv6 address
+
+ """
+ packed_ip = socket.inet_pton(socket.AF_INET6, address)
+ return socket.inet_ntop(socket.AF_INET6, packed_ip)
+
+
+def whataremyips(ring_ip=None):
+ """
+ Get "our" IP addresses ("us" being the set of services configured by
+ one `*.conf` file). If our REST listens on a specific address, return it.
+ Otherwise, if listen on '0.0.0.0' or '::' return all addresses, including
+ the loopback.
+
+ :param str ring_ip: Optional ring_ip/bind_ip from a config file; may be
+ IP address or hostname.
+ :returns: list of Strings of ip addresses
+ """
+ if ring_ip:
+ # See if bind_ip is '0.0.0.0'/'::'
+ try:
+ _, _, _, _, sockaddr = socket.getaddrinfo(
+ ring_ip, None, 0, socket.SOCK_STREAM, 0,
+ socket.AI_NUMERICHOST)[0]
+ if sockaddr[0] not in ('0.0.0.0', '::'):
+ return [ring_ip]
+ except socket.gaierror:
+ pass
+
+ addresses = []
+ for interface in netifaces.interfaces():
+ try:
+ iface_data = netifaces.ifaddresses(interface)
+ for family in iface_data:
+ if family not in (netifaces.AF_INET, netifaces.AF_INET6):
+ continue
+ for address in iface_data[family]:
+ addr = address['addr']
+
+ # If we have an ipv6 address remove the
+ # %ether_interface at the end
+ if family == netifaces.AF_INET6:
+ addr = expand_ipv6(addr.split('%')[0])
+ addresses.append(addr)
+ except ValueError:
+ pass
+ return addresses
+
+
+def parse_socket_string(socket_string, default_port):
+ """
+ Given a string representing a socket, returns a tuple of (host, port).
+ Valid strings are DNS names, IPv4 addresses, or IPv6 addresses, with an
+ optional port. If an IPv6 address is specified it **must** be enclosed in
+ [], like *[::1]* or *[::1]:11211*. This follows the accepted prescription
+ for `IPv6 host literals`_.
+
+ Examples::
+
+ server.org
+ server.org:1337
+ 127.0.0.1:1337
+ [::1]:1337
+ [::1]
+
+ .. _IPv6 host literals: https://tools.ietf.org/html/rfc3986#section-3.2.2
+ """
+ port = default_port
+ # IPv6 addresses must be between '[]'
+ if socket_string.startswith('['):
+ match = IPV6_RE.match(socket_string)
+ if not match:
+ raise ValueError("Invalid IPv6 address: %s" % socket_string)
+ host = match.group('address')
+ port = match.group('port') or port
+ else:
+ if ':' in socket_string:
+ tokens = socket_string.split(':')
+ if len(tokens) > 2:
+ raise ValueError("IPv6 addresses must be between '[]'")
+ host, port = tokens
+ else:
+ host = socket_string
+ return (host, port)
diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py
index d06bf5c967..9fee92bb91 100644
--- a/test/unit/common/test_utils.py
+++ b/test/unit/common/test_utils.py
@@ -65,7 +65,6 @@ from io import BytesIO
from shutil import rmtree
from functools import partial
from tempfile import TemporaryFile, NamedTemporaryFile, mkdtemp
-from netifaces import AF_INET6
from mock import MagicMock, patch
from six.moves.configparser import NoSectionError, NoOptionError
from uuid import uuid4
@@ -74,8 +73,7 @@ from swift.common.exceptions import Timeout, MessageTimeout, \
ConnectionTimeout, LockTimeout, ReplicationLockTimeout, \
MimeInvalid
from swift.common import utils
-from swift.common.utils import is_valid_ip, is_valid_ipv4, is_valid_ipv6, \
- set_swift_dir, md5, ShardRangeList
+from swift.common.utils import set_swift_dir, md5, ShardRangeList
from swift.common.container_sync_realms import ContainerSyncRealms
from swift.common.header_key_dict import HeaderKeyDict
from swift.common.storage_policy import POLICIES, reload_storage_policies
@@ -1511,132 +1509,6 @@ class TestUtils(unittest.TestCase):
self.assertEqual(utils.node_to_string(dev, replication=True),
'[fe80::0204:61ff:ff9d:1234]:6400/sdb')
- def test_is_valid_ip(self):
- self.assertTrue(is_valid_ip("127.0.0.1"))
- self.assertTrue(is_valid_ip("10.0.0.1"))
- ipv6 = "fe80:0000:0000:0000:0204:61ff:fe9d:f156"
- self.assertTrue(is_valid_ip(ipv6))
- ipv6 = "fe80:0:0:0:204:61ff:fe9d:f156"
- self.assertTrue(is_valid_ip(ipv6))
- ipv6 = "fe80::204:61ff:fe9d:f156"
- self.assertTrue(is_valid_ip(ipv6))
- ipv6 = "fe80:0000:0000:0000:0204:61ff:254.157.241.86"
- self.assertTrue(is_valid_ip(ipv6))
- ipv6 = "fe80:0:0:0:0204:61ff:254.157.241.86"
- self.assertTrue(is_valid_ip(ipv6))
- ipv6 = "fe80::204:61ff:254.157.241.86"
- self.assertTrue(is_valid_ip(ipv6))
- ipv6 = "fe80::"
- self.assertTrue(is_valid_ip(ipv6))
- ipv6 = "::1"
- self.assertTrue(is_valid_ip(ipv6))
- not_ipv6 = "3ffe:0b00:0000:0001:0000:0000:000a"
- self.assertFalse(is_valid_ip(not_ipv6))
- not_ipv6 = "1:2:3:4:5:6::7:8"
- self.assertFalse(is_valid_ip(not_ipv6))
-
- def test_is_valid_ipv4(self):
- self.assertTrue(is_valid_ipv4("127.0.0.1"))
- self.assertTrue(is_valid_ipv4("10.0.0.1"))
- ipv6 = "fe80:0000:0000:0000:0204:61ff:fe9d:f156"
- self.assertFalse(is_valid_ipv4(ipv6))
- ipv6 = "fe80:0:0:0:204:61ff:fe9d:f156"
- self.assertFalse(is_valid_ipv4(ipv6))
- ipv6 = "fe80::204:61ff:fe9d:f156"
- self.assertFalse(is_valid_ipv4(ipv6))
- ipv6 = "fe80:0000:0000:0000:0204:61ff:254.157.241.86"
- self.assertFalse(is_valid_ipv4(ipv6))
- ipv6 = "fe80:0:0:0:0204:61ff:254.157.241.86"
- self.assertFalse(is_valid_ipv4(ipv6))
- ipv6 = "fe80::204:61ff:254.157.241.86"
- self.assertFalse(is_valid_ipv4(ipv6))
- ipv6 = "fe80::"
- self.assertFalse(is_valid_ipv4(ipv6))
- ipv6 = "::1"
- self.assertFalse(is_valid_ipv4(ipv6))
- not_ipv6 = "3ffe:0b00:0000:0001:0000:0000:000a"
- self.assertFalse(is_valid_ipv4(not_ipv6))
- not_ipv6 = "1:2:3:4:5:6::7:8"
- self.assertFalse(is_valid_ipv4(not_ipv6))
-
- def test_is_valid_ipv6(self):
- self.assertFalse(is_valid_ipv6("127.0.0.1"))
- self.assertFalse(is_valid_ipv6("10.0.0.1"))
- ipv6 = "fe80:0000:0000:0000:0204:61ff:fe9d:f156"
- self.assertTrue(is_valid_ipv6(ipv6))
- ipv6 = "fe80:0:0:0:204:61ff:fe9d:f156"
- self.assertTrue(is_valid_ipv6(ipv6))
- ipv6 = "fe80::204:61ff:fe9d:f156"
- self.assertTrue(is_valid_ipv6(ipv6))
- ipv6 = "fe80:0000:0000:0000:0204:61ff:254.157.241.86"
- self.assertTrue(is_valid_ipv6(ipv6))
- ipv6 = "fe80:0:0:0:0204:61ff:254.157.241.86"
- self.assertTrue(is_valid_ipv6(ipv6))
- ipv6 = "fe80::204:61ff:254.157.241.86"
- self.assertTrue(is_valid_ipv6(ipv6))
- ipv6 = "fe80::"
- self.assertTrue(is_valid_ipv6(ipv6))
- ipv6 = "::1"
- self.assertTrue(is_valid_ipv6(ipv6))
- not_ipv6 = "3ffe:0b00:0000:0001:0000:0000:000a"
- self.assertFalse(is_valid_ipv6(not_ipv6))
- not_ipv6 = "1:2:3:4:5:6::7:8"
- self.assertFalse(is_valid_ipv6(not_ipv6))
-
- def test_expand_ipv6(self):
- expanded_ipv6 = "fe80::204:61ff:fe9d:f156"
- upper_ipv6 = "fe80:0000:0000:0000:0204:61ff:fe9d:f156"
- self.assertEqual(expanded_ipv6, utils.expand_ipv6(upper_ipv6))
- omit_ipv6 = "fe80:0000:0000::0204:61ff:fe9d:f156"
- self.assertEqual(expanded_ipv6, utils.expand_ipv6(omit_ipv6))
- less_num_ipv6 = "fe80:0:00:000:0204:61ff:fe9d:f156"
- self.assertEqual(expanded_ipv6, utils.expand_ipv6(less_num_ipv6))
-
- def test_whataremyips(self):
- myips = utils.whataremyips()
- self.assertTrue(len(myips) > 1)
- self.assertTrue('127.0.0.1' in myips)
-
- def test_whataremyips_bind_to_all(self):
- for any_addr in ('0.0.0.0', '0000:0000:0000:0000:0000:0000:0000:0000',
- '::0', '::0000', '::',
- # Wacky parse-error input produces all IPs
- 'I am a bear'):
- myips = utils.whataremyips(any_addr)
- self.assertTrue(len(myips) > 1)
- self.assertTrue('127.0.0.1' in myips)
-
- def test_whataremyips_bind_ip_specific(self):
- self.assertEqual(['1.2.3.4'], utils.whataremyips('1.2.3.4'))
-
- def test_whataremyips_error(self):
- def my_interfaces():
- return ['eth0']
-
- def my_ifaddress_error(interface):
- raise ValueError
-
- with patch('netifaces.interfaces', my_interfaces), \
- patch('netifaces.ifaddresses', my_ifaddress_error):
- self.assertEqual(utils.whataremyips(), [])
-
- def test_whataremyips_ipv6(self):
- test_ipv6_address = '2001:6b0:dead:beef:2::32'
- test_interface = 'eth0'
-
- def my_ipv6_interfaces():
- return ['eth0']
-
- def my_ipv6_ifaddresses(interface):
- return {AF_INET6:
- [{'netmask': 'ffff:ffff:ffff:ffff::',
- 'addr': '%s%%%s' % (test_ipv6_address, test_interface)}]}
- with patch('netifaces.interfaces', my_ipv6_interfaces), \
- patch('netifaces.ifaddresses', my_ipv6_ifaddresses):
- myips = utils.whataremyips()
- self.assertEqual(len(myips), 1)
- self.assertEqual(myips[0], test_ipv6_address)
-
def test_hash_path(self):
# Yes, these tests are deliberately very fragile. We want to make sure
# that if someones changes the results hash_path produces, they know it
diff --git a/test/unit/common/utils/test_ipaddrs.py b/test/unit/common/utils/test_ipaddrs.py
new file mode 100644
index 0000000000..3d49c595bf
--- /dev/null
+++ b/test/unit/common/utils/test_ipaddrs.py
@@ -0,0 +1,162 @@
+# Copyright (c) 2010-2012 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from mock import patch
+import socket
+import unittest
+
+# Continue importing from utils, as 3rd parties may depend on those imports
+from swift.common import utils
+from swift.common.utils import ipaddrs as utils_ipaddrs
+
+
+class TestIsValidIP(unittest.TestCase):
+ def test_is_valid_ip(self):
+ self.assertTrue(utils.is_valid_ip("127.0.0.1"))
+ self.assertTrue(utils.is_valid_ip("10.0.0.1"))
+ ipv6 = "fe80:0000:0000:0000:0204:61ff:fe9d:f156"
+ self.assertTrue(utils.is_valid_ip(ipv6))
+ ipv6 = "fe80:0:0:0:204:61ff:fe9d:f156"
+ self.assertTrue(utils.is_valid_ip(ipv6))
+ ipv6 = "fe80::204:61ff:fe9d:f156"
+ self.assertTrue(utils.is_valid_ip(ipv6))
+ ipv6 = "fe80:0000:0000:0000:0204:61ff:254.157.241.86"
+ self.assertTrue(utils.is_valid_ip(ipv6))
+ ipv6 = "fe80:0:0:0:0204:61ff:254.157.241.86"
+ self.assertTrue(utils.is_valid_ip(ipv6))
+ ipv6 = "fe80::204:61ff:254.157.241.86"
+ self.assertTrue(utils.is_valid_ip(ipv6))
+ ipv6 = "fe80::"
+ self.assertTrue(utils.is_valid_ip(ipv6))
+ ipv6 = "::1"
+ self.assertTrue(utils.is_valid_ip(ipv6))
+ not_ipv6 = "3ffe:0b00:0000:0001:0000:0000:000a"
+ self.assertFalse(utils.is_valid_ip(not_ipv6))
+ not_ipv6 = "1:2:3:4:5:6::7:8"
+ self.assertFalse(utils.is_valid_ip(not_ipv6))
+
+ def test_is_valid_ipv4(self):
+ self.assertTrue(utils.is_valid_ipv4("127.0.0.1"))
+ self.assertTrue(utils.is_valid_ipv4("10.0.0.1"))
+ ipv6 = "fe80:0000:0000:0000:0204:61ff:fe9d:f156"
+ self.assertFalse(utils.is_valid_ipv4(ipv6))
+ ipv6 = "fe80:0:0:0:204:61ff:fe9d:f156"
+ self.assertFalse(utils.is_valid_ipv4(ipv6))
+ ipv6 = "fe80::204:61ff:fe9d:f156"
+ self.assertFalse(utils.is_valid_ipv4(ipv6))
+ ipv6 = "fe80:0000:0000:0000:0204:61ff:254.157.241.86"
+ self.assertFalse(utils.is_valid_ipv4(ipv6))
+ ipv6 = "fe80:0:0:0:0204:61ff:254.157.241.86"
+ self.assertFalse(utils.is_valid_ipv4(ipv6))
+ ipv6 = "fe80::204:61ff:254.157.241.86"
+ self.assertFalse(utils.is_valid_ipv4(ipv6))
+ ipv6 = "fe80::"
+ self.assertFalse(utils.is_valid_ipv4(ipv6))
+ ipv6 = "::1"
+ self.assertFalse(utils.is_valid_ipv4(ipv6))
+ not_ipv6 = "3ffe:0b00:0000:0001:0000:0000:000a"
+ self.assertFalse(utils.is_valid_ipv4(not_ipv6))
+ not_ipv6 = "1:2:3:4:5:6::7:8"
+ self.assertFalse(utils.is_valid_ipv4(not_ipv6))
+
+ def test_is_valid_ipv6(self):
+ self.assertFalse(utils.is_valid_ipv6("127.0.0.1"))
+ self.assertFalse(utils.is_valid_ipv6("10.0.0.1"))
+ ipv6 = "fe80:0000:0000:0000:0204:61ff:fe9d:f156"
+ self.assertTrue(utils.is_valid_ipv6(ipv6))
+ ipv6 = "fe80:0:0:0:204:61ff:fe9d:f156"
+ self.assertTrue(utils.is_valid_ipv6(ipv6))
+ ipv6 = "fe80::204:61ff:fe9d:f156"
+ self.assertTrue(utils.is_valid_ipv6(ipv6))
+ ipv6 = "fe80:0000:0000:0000:0204:61ff:254.157.241.86"
+ self.assertTrue(utils.is_valid_ipv6(ipv6))
+ ipv6 = "fe80:0:0:0:0204:61ff:254.157.241.86"
+ self.assertTrue(utils.is_valid_ipv6(ipv6))
+ ipv6 = "fe80::204:61ff:254.157.241.86"
+ self.assertTrue(utils.is_valid_ipv6(ipv6))
+ ipv6 = "fe80::"
+ self.assertTrue(utils.is_valid_ipv6(ipv6))
+ ipv6 = "::1"
+ self.assertTrue(utils.is_valid_ipv6(ipv6))
+ not_ipv6 = "3ffe:0b00:0000:0001:0000:0000:000a"
+ self.assertFalse(utils.is_valid_ipv6(not_ipv6))
+ not_ipv6 = "1:2:3:4:5:6::7:8"
+ self.assertFalse(utils.is_valid_ipv6(not_ipv6))
+
+
+class TestExpandIPv6(unittest.TestCase):
+ def test_expand_ipv6(self):
+ expanded_ipv6 = "fe80::204:61ff:fe9d:f156"
+ upper_ipv6 = "fe80:0000:0000:0000:0204:61ff:fe9d:f156"
+ self.assertEqual(expanded_ipv6, utils.expand_ipv6(upper_ipv6))
+ omit_ipv6 = "fe80:0000:0000::0204:61ff:fe9d:f156"
+ self.assertEqual(expanded_ipv6, utils.expand_ipv6(omit_ipv6))
+ less_num_ipv6 = "fe80:0:00:000:0204:61ff:fe9d:f156"
+ self.assertEqual(expanded_ipv6, utils.expand_ipv6(less_num_ipv6))
+
+
+class TestWhatAreMyIPs(unittest.TestCase):
+ def test_whataremyips(self):
+ myips = utils.whataremyips()
+ self.assertTrue(len(myips) > 1)
+ self.assertIn('127.0.0.1', myips)
+
+ def test_whataremyips_bind_to_all(self):
+ for any_addr in ('0.0.0.0', '0000:0000:0000:0000:0000:0000:0000:0000',
+ '::0', '::0000', '::',
+ # Wacky parse-error input produces all IPs
+ 'I am a bear'):
+ myips = utils.whataremyips(any_addr)
+ self.assertTrue(len(myips) > 1)
+ self.assertIn('127.0.0.1', myips)
+
+ def test_whataremyips_bind_ip_specific(self):
+ self.assertEqual(['1.2.3.4'], utils.whataremyips('1.2.3.4'))
+
+ def test_whataremyips_netifaces_error(self):
+ class FakeNetifaces(object):
+ @staticmethod
+ def interfaces():
+ return ['eth0']
+
+ @staticmethod
+ def ifaddresses(interface):
+ raise ValueError
+
+ with patch.object(utils_ipaddrs, 'netifaces', FakeNetifaces):
+ self.assertEqual(utils.whataremyips(), [])
+
+ def test_whataremyips_netifaces_ipv6(self):
+ test_ipv6_address = '2001:6b0:dead:beef:2::32'
+ test_interface = 'eth0'
+
+ class FakeNetifaces(object):
+ AF_INET = int(socket.AF_INET)
+ AF_INET6 = int(socket.AF_INET6)
+
+ @staticmethod
+ def interfaces():
+ return ['eth0']
+
+ @staticmethod
+ def ifaddresses(interface):
+ return {int(socket.AF_INET6): [
+ {'netmask': 'ffff:ffff:ffff:ffff::',
+ 'addr': '%s%%%s' % (test_ipv6_address, test_interface)}]}
+
+ with patch.object(utils_ipaddrs, 'netifaces', FakeNetifaces):
+ myips = utils.whataremyips()
+ self.assertEqual(len(myips), 1)
+ self.assertEqual(myips[0], test_ipv6_address)