Add both IPv4 and IPv6 DHCP options if interface has both
It is possible that an interface has both IPv4 and IPv6 addresses, primarily when using SLAAC with OpenStack Neutron. When this is the case, it is very likely that the first fixed IP would be a SLAAC assigned port and the second IP is the IPv4 address. In an environment where you are looking to boot via IPv4, no DHCPv6 infrastructure exists as IPv6 connectivity is provided via SLAAC, you would not be able to use this network to boot off of. This patch instead grabs all the fixed IP addresses, then inserts the options that match the IP versions which are attached to the interface, potentially resulting in both IPv4 and IPv6 options being included (though the IPv6 ones would be largely omitted). In environments where only IPv4 or IPv6 is in use on the port, it will still only insert the options for those specific IP versions. Story #2008660 Task #41933 Change-Id: I52e4ee022b17cb7f007534cb368136567b139a34
This commit is contained in:
parent
f5d9cabef2
commit
367cdcd665
@ -64,9 +64,8 @@ class NeutronDHCPApi(base.BaseDHCP):
|
|||||||
try:
|
try:
|
||||||
neutron_client = neutron.get_client(token=token, context=context)
|
neutron_client = neutron.get_client(token=token, context=context)
|
||||||
|
|
||||||
fip = None
|
fips = []
|
||||||
port = neutron_client.get_port(port_id)
|
port = neutron_client.get_port(port_id)
|
||||||
try:
|
|
||||||
if port:
|
if port:
|
||||||
# TODO(TheJulia): We need to retool this down the
|
# TODO(TheJulia): We need to retool this down the
|
||||||
# road so that we handle ports and allow preferences
|
# road so that we handle ports and allow preferences
|
||||||
@ -77,12 +76,13 @@ class NeutronDHCPApi(base.BaseDHCP):
|
|||||||
# with UEFI machines, so the support matrix also gets
|
# with UEFI machines, so the support matrix also gets
|
||||||
# a little "weird".
|
# a little "weird".
|
||||||
# Ideally, we should work on this in Victoria.
|
# Ideally, we should work on this in Victoria.
|
||||||
fip = port.get('fixed_ips')[0]
|
fips = port.get('fixed_ips')
|
||||||
except (TypeError, IndexError):
|
|
||||||
fip = None
|
|
||||||
update_opts = []
|
update_opts = []
|
||||||
if fip:
|
if len(fips) != 0:
|
||||||
ip_version = ipaddress.ip_address(fip['ip_address']).version
|
for fip in fips:
|
||||||
|
ip_version = \
|
||||||
|
ipaddress.ip_address(fip['ip_address']).version
|
||||||
for option in dhcp_options:
|
for option in dhcp_options:
|
||||||
if option.get('ip_version', 4) == ip_version:
|
if option.get('ip_version', 4) == ip_version:
|
||||||
update_opts.append(option)
|
update_opts.append(option)
|
||||||
|
@ -119,6 +119,66 @@ class TestNeutron(db_base.DbTestCase):
|
|||||||
update_mock.assert_called_once_with(
|
update_mock.assert_called_once_with(
|
||||||
task.context, port_id, expected)
|
task.context, port_id, expected)
|
||||||
|
|
||||||
|
@mock.patch('ironic.common.neutron.get_client', autospec=True)
|
||||||
|
@mock.patch('ironic.common.neutron.update_neutron_port', autospec=True)
|
||||||
|
def test_update_port_dhcp_opts_v4_and_v6(self, update_mock, client_mock):
|
||||||
|
opts = [{'opt_name': 'bootfile-name',
|
||||||
|
'opt_value': 'pxelinux.0',
|
||||||
|
'ip_version': 4},
|
||||||
|
{'opt_name': 'tftp-server',
|
||||||
|
'opt_value': '1.1.1.1',
|
||||||
|
'ip_version': 4},
|
||||||
|
{'opt_name': 'server-ip-address',
|
||||||
|
'opt_value': '1.1.1.1',
|
||||||
|
'ip_version': 4},
|
||||||
|
{'opt_name': 'bootfile-url',
|
||||||
|
'opt_value': 'tftp://::1/file.name',
|
||||||
|
'ip_version': 6}]
|
||||||
|
port_id = 'fake-port-id'
|
||||||
|
expected = {
|
||||||
|
'extra_dhcp_opts': [
|
||||||
|
{
|
||||||
|
'opt_name': 'bootfile-name',
|
||||||
|
'opt_value': 'pxelinux.0',
|
||||||
|
'ip_version': 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'opt_name': 'tftp-server',
|
||||||
|
'opt_value': '1.1.1.1',
|
||||||
|
'ip_version': 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'opt_name': 'server-ip-address',
|
||||||
|
'opt_value': '1.1.1.1',
|
||||||
|
'ip_version': 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'opt_name': 'bootfile-url',
|
||||||
|
'opt_value': 'tftp://::1/file.name',
|
||||||
|
'ip_version': 6
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
port_data = {
|
||||||
|
"id": port_id,
|
||||||
|
"fixed_ips": [
|
||||||
|
{
|
||||||
|
"ip_address": "192.168.1.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ip_address": "2001:db8::201",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
client_mock.return_value.get_port.return_value = port_data
|
||||||
|
|
||||||
|
api = dhcp_factory.DHCPFactory()
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
|
api.provider.update_port_dhcp_opts(port_id, opts,
|
||||||
|
context=task.context)
|
||||||
|
update_mock.assert_called_once_with(
|
||||||
|
task.context, port_id, expected)
|
||||||
|
|
||||||
@mock.patch('ironic.common.neutron.get_client', autospec=True)
|
@mock.patch('ironic.common.neutron.get_client', autospec=True)
|
||||||
@mock.patch('ironic.common.neutron.update_neutron_port', autospec=True)
|
@mock.patch('ironic.common.neutron.update_neutron_port', autospec=True)
|
||||||
def test_update_port_dhcp_opts_with_exception(self, update_mock,
|
def test_update_port_dhcp_opts_with_exception(self, update_mock,
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- When using the Neutron DHCP driver, Ironic would only use the first fixed
|
||||||
|
IP address to determine what IP versions are use on the port. Now, it
|
||||||
|
checks for all the IP addresses and adds DHCP options for all IP versions.
|
Loading…
Reference in New Issue
Block a user