Merge "Advertise the correct address when using IPv6"

This commit is contained in:
Jenkins 2017-01-12 12:05:43 +00:00 committed by Gerrit Code Review
commit 51ab461af8
7 changed files with 85 additions and 2 deletions

View File

@ -210,7 +210,7 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
return
try:
return out.strip().split('\n')[0].split('src')[1].strip()
return out.strip().split('\n')[0].split('src')[1].split()[0]
except IndexError:
LOG.warning('No route to host %(dest)s, route record: %(rec)s',
{'dest': dest, 'rec': out})

View File

@ -20,6 +20,7 @@ import requests
from ironic_python_agent import encoding
from ironic_python_agent import errors
from ironic_python_agent import netutils
LOG = log.getLogger(__name__)
@ -141,5 +142,5 @@ class APIClient(object):
raise loopingcall.LoopingCallDone(retvalue=content)
def _get_agent_url(self, advertise_address):
return 'http://{}:{}'.format(advertise_address[0],
return 'http://{}:{}'.format(netutils.wrap_ipv6(advertise_address[0]),
advertise_address[1])

View File

@ -22,6 +22,7 @@ import sys
import netifaces
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import netutils
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@ -213,3 +214,9 @@ def interface_has_carrier(interface_name):
LOG.debug('No carrier information for interface %s',
interface_name)
return False
def wrap_ipv6(ip):
if netutils.is_valid_ipv6(ip):
return "[%s]" % ip
return ip

View File

@ -466,6 +466,22 @@ class TestBaseAgent(test_base.BaseTestCase):
self.assertRaises(errors.UnknownNodeError,
self.agent.get_node_uuid)
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_route_source(self, mock_execute):
mock_execute.return_value = ('XXX src 1.2.3.4 XXX\n cache', None)
source = self.agent._get_route_source('XXX')
self.assertEqual('1.2.3.4', source)
@mock.patch.object(agent, 'LOG', autospec=True)
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_route_source_indexerror(self, mock_execute, mock_log):
mock_execute.return_value = ('XXX src \n cache', None)
source = self.agent._get_route_source('XXX')
self.assertIsNone(source)
mock_log.warning.assert_called_once()
@mock.patch.object(hardware.GenericHardwareManager, '_wait_for_disks',
lambda self: None)
@ -597,6 +613,22 @@ class TestAdvertiseAddress(test_base.BaseTestCase):
mock_exec.assert_called_once_with('ip', 'route', 'get', '1.2.1.2')
mock_gethostbyname.assert_called_once_with('1.2.1.2')
def test_route_with_ipv6(self, mock_exec, mock_gethostbyname):
self.agent.api_url = 'http://[fc00:1111::1]:8081/v1'
mock_gethostbyname.side_effect = socket.gaierror()
mock_exec.return_value = (
"""fc00:101::1 dev br-ctlplane src fc00:101::4 metric 0
cache """,
""
)
self.agent.set_agent_advertise_addr()
self.assertEqual(('fc00:101::4', 9990),
self.agent.advertise_address)
mock_exec.assert_called_once_with('ip', 'route', 'get', 'fc00:1111::1')
mock_gethostbyname.assert_called_once_with('fc00:1111::1')
def test_route_with_host(self, mock_exec, mock_gethostbyname):
mock_gethostbyname.return_value = '1.2.1.2'
mock_exec.return_value = (

View File

@ -70,8 +70,29 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase):
heartbeat_path = 'v1/heartbeat/deadbeef-dabb-ad00-b105-f00d00bab10c'
request_args = self.api_client.session.request.call_args[0]
data = self.api_client.session.request.call_args[1]['data']
self.assertEqual('POST', request_args[0])
self.assertEqual(API_URL + heartbeat_path, request_args[1])
self.assertEqual('{"callback_url": "http://192.0.2.1:9999"}', data)
def test_successful_heartbeat_ip6(self):
response = FakeResponse(status_code=202)
self.api_client.session.request = mock.Mock()
self.api_client.session.request.return_value = response
self.api_client.heartbeat(
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
advertise_address=('fc00:1111::4', '9999')
)
heartbeat_path = 'v1/heartbeat/deadbeef-dabb-ad00-b105-f00d00bab10c'
request_args = self.api_client.session.request.call_args[0]
data = self.api_client.session.request.call_args[1]['data']
self.assertEqual('POST', request_args[0])
self.assertEqual(API_URL + heartbeat_path, request_args[1])
self.assertEqual('{"callback_url": "http://[fc00:1111::4]:9999"}',
data)
def test_heartbeat_requests_exception(self):
self.api_client.session.request = mock.Mock()
@ -240,3 +261,11 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase):
node_uuid=None)
self.assertFalse(error)
def test_get_agent_url_ipv4(self):
url = self.api_client._get_agent_url(('1.2.3.4', '9999'))
self.assertEqual('http://1.2.3.4:9999', url)
def test_get_agent_url_ipv6(self):
url = self.api_client._get_agent_url(('1:2::3:4', '9999'))
self.assertEqual('http://[1:2::3:4]:9999', url)

View File

@ -336,3 +336,11 @@ class TestNetutils(test_base.BaseTestCase):
sock1.close.assert_called_once_with()
sock2.close.assert_called_once_with()
def test_wrap_ipv6(self):
res = netutils.wrap_ipv6('1:2::3:4')
self.assertEqual('[1:2::3:4]', res)
def test_wrap_ipv6_with_ipv4(self):
res = netutils.wrap_ipv6('1.2.3.4')
self.assertEqual('1.2.3.4', res)

View File

@ -0,0 +1,6 @@
---
fixes:
- Ironic Python Agent now correctly detects its IPv6 address
if communicating with ironic over IPv6. This address is also
wrapped in square brackets if the address being advertised
is IPv6.