Correctly detect IPv6 addresses

Use the is_ip function from charmhelpers to correctly
detect and return IPv4 and IPv6 addresses.

Support DNS querying for IPv6 addresses using ipv6
argument (defaults to false).

Resync tox.ini from release tools to resolve libcharmstore
compatibility issues for 1.25.x testing.

Change-Id: I719ac7db350b2b257ae057acc4299a8e97501a7b
Partial-Bug: 1622780
This commit is contained in:
James Page 2017-03-08 11:08:13 +00:00
parent 60e58482f6
commit bb30f468aa
3 changed files with 68 additions and 8 deletions

View File

@ -46,6 +46,7 @@ from charmhelpers.fetch import (
from charmhelpers.contrib.network.ip import (
get_address_in_network,
get_ipv6_addr,
is_ip,
)
from charmhelpers.contrib.database.mysql import (
MySQLHelper,
@ -110,11 +111,11 @@ def setup_percona_repo():
subprocess.check_call(['apt-key', 'add', KEY])
def resolve_hostname_to_ip(hostname):
def resolve_hostname_to_ip(hostname, ipv6=False):
"""Resolve hostname to IP
@param hostname: hostname to be resolved
@returns IP address
@returns IP address or None if resolution was not possible via DNS
"""
try:
import dns.resolver
@ -123,14 +124,16 @@ def resolve_hostname_to_ip(hostname):
fatal=True)
import dns.resolver
try:
# Test to see if already an IPv4 address
socket.inet_aton(hostname)
if is_ip(hostname):
return hostname
except socket.error:
else:
if ipv6:
query_type = 'AAAA'
else:
query_type = 'A'
# This may throw an NXDOMAIN exception; in which case
# things are badly broken so just let it kill the hook
answers = dns.resolver.query(hostname, 'A')
answers = dns.resolver.query(hostname, query_type)
if answers:
return answers[0].address

View File

@ -14,13 +14,18 @@ install_command =
pip install --allow-unverified python-apt {opts} {packages}
commands = ostestr {posargs}
whitelist_externals = juju
passenv = HOME TERM AMULET_*
passenv = HOME TERM AMULET_* CS_API_URL
[testenv:py27]
basepython = python2.7
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
[testenv:py35]
basepython = python3.5
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
[testenv:pep8]
basepython = python2.7
deps = -r{toxinidir}/requirements.txt

View File

@ -460,3 +460,55 @@ class UtilsTestsCTC(CharmTestCase):
self.is_leader.return_value = True
mock_cluster_ready.return_value = True
self.assertTrue(percona_utils.leader_node_is_ready())
class TestResolveHostnameToIP(CharmTestCase):
TO_PATCH = []
def setUp(self):
CharmTestCase.setUp(self, percona_utils,
self.TO_PATCH)
def test_resolve_hostname_to_ip_ips(self):
ipv6_address = '2a01:348:2f4:0:dba7:dc58:659b:941f'
ipv4_address = '10.10.10.2'
self.assertEqual(percona_utils.resolve_hostname_to_ip(ipv6_address),
ipv6_address)
self.assertEqual(percona_utils.resolve_hostname_to_ip(ipv4_address),
ipv4_address)
@mock.patch('dns.resolver.query')
def test_resolve_hostname_to_ip_hostname_a(self,
dns_query):
mock_answer = mock.MagicMock()
mock_answer.address = '10.10.10.20'
dns_query.return_value = [mock_answer]
self.assertEqual(percona_utils.resolve_hostname_to_ip('myhostname'),
'10.10.10.20')
dns_query.assert_has_calls([
mock.call('myhostname', 'A'),
])
@mock.patch('dns.resolver.query')
def test_resolve_hostname_to_ip_hostname_aaaa(self,
dns_query):
mock_answer = mock.MagicMock()
mock_answer.address = '2a01:348:2f4:0:dba7:dc58:659b:941f'
dns_query.return_value = [mock_answer]
self.assertEqual(percona_utils.resolve_hostname_to_ip('myhostname',
ipv6=True),
'2a01:348:2f4:0:dba7:dc58:659b:941f')
dns_query.assert_has_calls([
mock.call('myhostname', 'AAAA'),
])
@mock.patch('dns.resolver.query')
def test_resolve_hostname_to_ip_hostname_noanswer(self,
dns_query):
dns_query.return_value = []
self.assertEqual(percona_utils.resolve_hostname_to_ip('myhostname'),
None)
dns_query.assert_has_calls([
mock.call('myhostname', 'A'),
])