Inventoried MAC address for only ipv6 addresses

Extended the function that expose BMC MAC address in inventory data
for an IPv6 only interface.
Previously, if no IPv4 address was configured, no mac address was exposed.

Change-Id: I93e49d308cfd63be1c09749ced4428a87a3daff9
This commit is contained in:
Maximilian Brandt 2024-11-07 15:20:25 +01:00
parent 5746ac1222
commit 6ccd3965ff
3 changed files with 143 additions and 3 deletions

View File

@ -2464,8 +2464,34 @@ class GenericHardwareManager(HardwareManager):
continue
if ip == "0.0.0.0":
# disabled, ignore
continue
# Check if we have IPv6 address configured
out, e = il_utils.execute(
"ipmitool lan6 print {} | awk '/^IPv6"
" (Dynamic|Static) Address [0-9]+:/"
" {{in_section=1; next}} /^IPv6 / {{in_section=0}}"
" in_section && /Address:/ {{print $2}}'".
format(channel), shell=True)
if e.startswith("Invalid channel"):
continue
valid_ipv6_found = False
try:
ipv6_list = out.strip().split("\n")
# Skip auto-configured link-local addresses
# and ignore "::/255", which indicates unconfigured
# addresses returned by ipmitool.
valid_ipv6_found = any(
not ipv6.startswith("::")
and not ipv6.startswith("fe80")
for ipv6 in ipv6_list
)
except ValueError:
LOG.warning('Invalid ipmitool output %(output)s',
{'output': out})
continue
if not valid_ipv6_found:
continue
if not re.match("^[0-9a-f]{2}(:[0-9a-f]{2}){5}$", mac, re.I):
LOG.warning('Invalid MAC address %(output)s',

View File

@ -3185,16 +3185,125 @@ class TestGenericHardwareManager(base.IronicAgentTest):
return '', 'Invalid channel 1\n'
elif args[0].startswith("ipmitool lan print 2"):
return '0.0.0.0\n00:00:00:00:23:42', ''
elif args[0].startswith("ipmitool lan6 print"):
return '::/255', ''
elif args[0].startswith("ipmitool lan print 3"):
return 'meow', ''
elif args[0].startswith("ipmitool lan print 4"):
return '192.1.2.3\n01:02:03:04:05:06', ''
else:
# this should never happen because the previous one was good
raise AssertionError
mocked_execute.side_effect = side_effect
self.assertEqual('01:02:03:04:05:06', self.hardware.get_bmc_mac())
@mock.patch.object(hardware.GenericHardwareManager,
'any_ipmi_device_exists', autospec=True)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_get_bmc_mac_for_ipv6(self, mocked_execute,
mock_ipmi_device_exists):
mock_ipmi_device_exists.return_value = True
def side_effect(*args, **kwargs):
if args[0].startswith("ipmitool lan print"):
return '0.0.0.0\n01:02:03:04:05:06', ''
elif args[0].startswith("ipmitool lan6 print"):
return '2001:db8::/32', ''
else:
raise AssertionError
mocked_execute.side_effect = side_effect
self.assertEqual('01:02:03:04:05:06', self.hardware.get_bmc_mac())
@mock.patch.object(hardware.GenericHardwareManager,
'any_ipmi_device_exists', autospec=True)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_get_bmc_mac_with_invalid_ipv6(self, mocked_execute,
mock_ipmi_device_exists):
mock_ipmi_device_exists.return_value = True
def side_effect(*args, **kwargs):
if args[0].startswith("ipmitool lan print"):
return '0.0.0.0\n01:02:03:04:05:06', ''
elif args[0].startswith("ipmitool lan6 print"):
return '::/255', ''
else:
raise AssertionError
mocked_execute.side_effect = side_effect
self.assertRaises(errors.IncompatibleHardwareMethodError,
self.hardware.get_bmc_mac)
@mock.patch.object(hardware.GenericHardwareManager,
'any_ipmi_device_exists', autospec=True)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_get_bmc_mac_with_valid_ipv6_and_invalid_mac(
self, mocked_execute, mock_ipmi_device_exists):
mock_ipmi_device_exists.return_value = True
def side_effect(*args, **kwargs):
if args[0].startswith("ipmitool lan print"):
return '0.0.0.0\n00:00:00:00:00:00', ''
elif args[0].startswith("ipmitool lan6 print"):
return '2001:db8::/32', ''
else:
raise AssertionError
mocked_execute.side_effect = side_effect
self.assertRaises(errors.IncompatibleHardwareMethodError,
self.hardware.get_bmc_mac)
@mock.patch.object(hardware.GenericHardwareManager,
'any_ipmi_device_exists', autospec=True)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_get_bmc_mac_no_valid_ip_or_ipv6(self,
mocked_execute,
mock_ipmi_device_exists):
mock_ipmi_device_exists.return_value = True
def side_effect(*args, **kwargs):
if args[0].startswith("ipmitool lan print"):
return '0.0.0.0\n00:00:00:00:00:00', ''
elif args[0].startswith("ipmitool lan6 print"):
return '::/255', ''
else:
raise AssertionError
mocked_execute.side_effect = side_effect
self.assertRaises(errors.IncompatibleHardwareMethodError,
self.hardware.get_bmc_mac)
@mock.patch.object(hardware.GenericHardwareManager,
'any_ipmi_device_exists', autospec=True)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_get_bmc_mac_iterate_channels_ipv6(self,
mocked_execute,
mock_ipmi_device_exists):
mock_ipmi_device_exists.return_value = True
# For channel 4 we simulate configured IPv6 and MAC
def side_effect(*args, **kwargs):
if args[0].startswith("ipmitool lan print 1"):
return '', 'Invalid channel 1\n'
elif args[0].startswith("ipmitool lan print 2"):
return 'meow', ''
elif args[0].startswith("ipmitool lan6 print 1"):
return '', 'Invalid channel 1\n'
elif args[0].startswith("ipmitool lan6 print 2"):
return 'meow', ''
elif args[0].startswith("ipmitool lan print 3"):
return '0.0.0.0\n00:00:00:00:01:02', ''
elif args[0].startswith("ipmitool lan6 print 3"):
return 'fe80::/64', ''
elif args[0].startswith("ipmitool lan print 4"):
return '0.0.0.0\n01:02:03:04:05:06', ''
elif args[0].startswith("ipmitool lan6 print 4"):
return '2001:db8::/32', ''
else:
raise AssertionError
mocked_execute.side_effect = side_effect
self.assertEqual('01:02:03:04:05:06', self.hardware.get_bmc_mac())
@mock.patch.object(hardware.GenericHardwareManager,
'any_ipmi_device_exists', autospec=True)
@mock.patch.object(il_utils, 'execute', autospec=True)

View File

@ -0,0 +1,5 @@
---
features:
- |
Adds support for detecting MAC addresses for interfaces with
only a IPv6 address.