Add bmc_subnet information to introspection
Consolidated BMC information retrieval logic into a single function _get_bmc_info(). Add tests for bmc_subnet Change-Id: If865e10f910d9e00a68106d97cc85bd53b4a86ed
This commit is contained in:
parent
af907322f6
commit
50e682b5cd
|
@ -142,7 +142,7 @@ def _load_multipath_modules():
|
|||
will do the needful.
|
||||
"""
|
||||
if (os.path.isfile('/usr/sbin/mpathconf')
|
||||
and not os.path.isfile('/etc/multipath.conf')):
|
||||
and not os.path.isfile('/etc/multipath.conf')):
|
||||
# For Centos/Rhel/Etc which uses mpathconf, this does
|
||||
# a couple different things, including configuration generation...
|
||||
# which is not *really* required.. at least *shouldn't* be.
|
||||
|
@ -846,6 +846,7 @@ class CPU(encoding.SerializableComparable):
|
|||
|
||||
class Memory(encoding.SerializableComparable):
|
||||
serializable_fields = ('total', 'physical_mb')
|
||||
|
||||
# physical = total + kernel binary + reserved space
|
||||
|
||||
def __init__(self, total, physical_mb=None):
|
||||
|
@ -944,6 +945,9 @@ class HardwareManager(object, metaclass=abc.ABCMeta):
|
|||
def get_bmc_address(self):
|
||||
raise errors.IncompatibleHardwareMethodError()
|
||||
|
||||
def get_bmc_subnet(self):
|
||||
raise errors.IncompatibleHardwareMethodError()
|
||||
|
||||
def get_bmc_mac(self):
|
||||
raise errors.IncompatibleHardwareMethodError()
|
||||
|
||||
|
@ -1082,6 +1086,7 @@ class HardwareManager(object, metaclass=abc.ABCMeta):
|
|||
hardware_info['disks'] = self.list_block_devices()
|
||||
hardware_info['memory'] = self.get_memory()
|
||||
hardware_info['bmc_address'] = self.get_bmc_address()
|
||||
hardware_info['bmc_subnet'] = self.get_bmc_subnet()
|
||||
hardware_info['bmc_v6address'] = self.get_bmc_v6address()
|
||||
hardware_info['system_vendor'] = self.get_system_vendor_info()
|
||||
hardware_info['boot'] = self.get_boot_info()
|
||||
|
@ -1977,7 +1982,7 @@ class GenericHardwareManager(HardwareManager):
|
|||
args = ('shred', '--force')
|
||||
|
||||
if info.get('agent_erase_devices_zeroize', True):
|
||||
args += ('--zero', )
|
||||
args += ('--zero',)
|
||||
|
||||
args += ('--verbose', '--iterations', str(npasses), block_device.name)
|
||||
|
||||
|
@ -2000,7 +2005,7 @@ class GenericHardwareManager(HardwareManager):
|
|||
if os.path.exists(vm_device_label):
|
||||
link = os.readlink(vm_device_label)
|
||||
device = os.path.normpath(os.path.join(os.path.dirname(
|
||||
vm_device_label), link))
|
||||
vm_device_label), link))
|
||||
if block_device.name == device:
|
||||
return True
|
||||
return False
|
||||
|
@ -2048,7 +2053,7 @@ class GenericHardwareManager(HardwareManager):
|
|||
except IOError as e:
|
||||
# Check underlying device as the file may exist there
|
||||
if (not partition and dev_name[-1].isdigit()
|
||||
and 'nvme' not in dev_name):
|
||||
and 'nvme' not in dev_name):
|
||||
return self._is_read_only_device(block_device, partition=True)
|
||||
|
||||
LOG.warning("Could not determine if %(name)s is a"
|
||||
|
@ -2259,9 +2264,9 @@ class GenericHardwareManager(HardwareManager):
|
|||
# instead
|
||||
crypto_caps = nvme_info['fna']
|
||||
if crypto_caps & NVME_CLI_CRYPTO_FORMAT_SUPPORTED_FLAG:
|
||||
format_mode = 2 # crypto erase
|
||||
format_mode = 2 # crypto erase
|
||||
else:
|
||||
format_mode = 1 # user-data erase
|
||||
format_mode = 1 # user-data erase
|
||||
else:
|
||||
msg = ('nvme-cli did not return any supported format modes '
|
||||
'for device: {device}').format(
|
||||
|
@ -2289,11 +2294,13 @@ class GenericHardwareManager(HardwareManager):
|
|||
).format(block_device, e))
|
||||
raise errors.BlockDeviceEraseError(msg)
|
||||
|
||||
def get_bmc_address(self):
|
||||
"""Attempt to detect BMC IP address
|
||||
def _get_bmc_address_info(self, type):
|
||||
"""Attempt to detect BMC information
|
||||
|
||||
:return: IP address of lan channel or 0.0.0.0 in case none of them is
|
||||
configured properly
|
||||
:param type: Keyword to search for in IPMITool output
|
||||
(e.g., 'IP Address', 'Subnet Mask')
|
||||
:return: BMC information (IP address or subnet mask) or
|
||||
default value if none found
|
||||
"""
|
||||
try:
|
||||
# From all the channels 0-15, only 1-11 can be assigned to
|
||||
|
@ -2301,8 +2308,8 @@ class GenericHardwareManager(HardwareManager):
|
|||
# effectively used
|
||||
for channel in range(1, 12):
|
||||
out, e = il_utils.execute(
|
||||
"ipmitool lan print {} | awk '/IP Address[ \\t]*:/"
|
||||
" {{print $4}}'".format(channel), shell=True)
|
||||
"ipmitool lan print {} | awk '/{}[ \\t]*:/"
|
||||
" {{print $4}}'".format(channel, type), shell=True)
|
||||
if e.startswith("Invalid channel"):
|
||||
continue
|
||||
out = out.strip()
|
||||
|
@ -2310,7 +2317,8 @@ class GenericHardwareManager(HardwareManager):
|
|||
try:
|
||||
ipaddress.ip_address(out)
|
||||
except ValueError as exc:
|
||||
LOG.warning('Invalid IP address %(output)s: %(exc)s',
|
||||
LOG.warning('Invalid IP or Subnet address %(output)s: '
|
||||
'%(exc)s',
|
||||
{'output': out, 'exc': exc})
|
||||
continue
|
||||
|
||||
|
@ -2321,11 +2329,33 @@ class GenericHardwareManager(HardwareManager):
|
|||
|
||||
except (processutils.ProcessExecutionError, OSError) as e:
|
||||
# Not error, because it's normal in virtual environment
|
||||
LOG.warning("Cannot get BMC address: %s", e)
|
||||
LOG.warning("Cannot get BMC %s: %s", type, e)
|
||||
return
|
||||
|
||||
return '0.0.0.0'
|
||||
|
||||
def get_bmc_address(self):
|
||||
"""Attempt to detect BMC subnet mask
|
||||
|
||||
:return: Subnet mask of the first
|
||||
LAN channel or 0.0.0.0 if none
|
||||
of them is configured properly
|
||||
"""
|
||||
bmc_address = self._get_bmc_address_info("IP Address")
|
||||
return bmc_address
|
||||
|
||||
def get_bmc_subnet(self):
|
||||
"""Attempt to detect BMC subnet mask
|
||||
|
||||
:return: Subnet mask of the first
|
||||
LAN channel or 255.255.255.255 if none
|
||||
of them is configured properly
|
||||
"""
|
||||
bmc_subnet = self._get_bmc_address_info("Subnet Mask")
|
||||
if bmc_subnet == '0.0.0.0':
|
||||
return '255.255.255.255'
|
||||
return bmc_subnet
|
||||
|
||||
def get_bmc_mac(self):
|
||||
"""Attempt to detect BMC MAC address
|
||||
|
||||
|
@ -2902,7 +2932,7 @@ class GenericHardwareManager(HardwareManager):
|
|||
if not raid_devices:
|
||||
break
|
||||
else:
|
||||
msg = "Unable to clean all softraid correctly. Remaining {}".\
|
||||
msg = "Unable to clean all softraid correctly. Remaining {}". \
|
||||
format([dev.name for dev in raid_devices])
|
||||
LOG.error(msg)
|
||||
raise errors.SoftwareRAIDError(msg)
|
||||
|
@ -2969,7 +2999,7 @@ class GenericHardwareManager(HardwareManager):
|
|||
continue
|
||||
else:
|
||||
msg = "Failed to examine device {}: {}".format(
|
||||
component_device, e)
|
||||
component_device, e)
|
||||
raise errors.SoftwareRAIDError(msg)
|
||||
|
||||
LOG.debug('Deleting md superblock on %s', component_device)
|
||||
|
|
|
@ -1044,6 +1044,7 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
|||
current_boot_mode='bios', pxe_interface='boot:if')
|
||||
|
||||
self.hardware.get_bmc_address = mock.Mock()
|
||||
self.hardware.get_bmc_subnet = mock.Mock()
|
||||
self.hardware.get_bmc_mac = mock.Mock()
|
||||
self.hardware.get_bmc_v6address = mock.Mock()
|
||||
self.hardware.get_system_vendor_info = mock.Mock()
|
||||
|
@ -2908,6 +2909,55 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
|||
mocked_execute.return_value = '', ''
|
||||
self.assertEqual('0.0.0.0', self.hardware.get_bmc_address())
|
||||
|
||||
@mock.patch.object(il_utils, 'execute', autospec=True)
|
||||
def test_get_bmc_subnet(self, mocked_execute):
|
||||
mocked_execute.return_value = '255.255.255.0\n', ''
|
||||
self.assertEqual('255.255.255.0', self.hardware.get_bmc_subnet())
|
||||
|
||||
@mock.patch.object(il_utils, 'execute', autospec=True)
|
||||
def test_get_bmc_subnet_virt(self, mocked_execute):
|
||||
mocked_execute.side_effect = processutils.ProcessExecutionError()
|
||||
self.assertIsNone(self.hardware.get_bmc_subnet())
|
||||
|
||||
@mock.patch.object(il_utils, 'execute', autospec=True)
|
||||
def test_get_bmc_subnet_zeroed(self, mocked_execute):
|
||||
mocked_execute.return_value = '0.0.0.0\n', ''
|
||||
self.assertEqual('255.255.255.255', self.hardware.get_bmc_subnet())
|
||||
|
||||
@mock.patch.object(il_utils, 'execute', autospec=True)
|
||||
def test_get_bmc_subnet_invalid(self, mocked_execute):
|
||||
# In case of invalid lan channel, stdout is empty and the error
|
||||
# on stderr is "Invalid channel"
|
||||
mocked_execute.return_value = '\n', 'Invalid channel: 55'
|
||||
self.assertEqual('255.255.255.255', self.hardware.get_bmc_subnet())
|
||||
|
||||
@mock.patch.object(il_utils, 'execute', autospec=True)
|
||||
def test_get_bmc_subnet_random_error(self, mocked_execute):
|
||||
mocked_execute.return_value = '255.255.255.0\n', 'Random error message'
|
||||
self.assertEqual('255.255.255.0', self.hardware.get_bmc_subnet())
|
||||
|
||||
@mock.patch.object(il_utils, 'execute', autospec=True)
|
||||
def test_get_bmc_subnet_iterate_channels(self, mocked_execute):
|
||||
# For channel 1 we simulate unconfigured subnet
|
||||
# and for any other we return a correct subnet address
|
||||
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 '255.255.255.255\n', ''
|
||||
elif args[0].startswith("ipmitool lan print 3"):
|
||||
return 'meow', ''
|
||||
else:
|
||||
return '255.255.255.0\n', ''
|
||||
|
||||
mocked_execute.side_effect = side_effect
|
||||
self.assertEqual('255.255.255.255', self.hardware.get_bmc_subnet())
|
||||
|
||||
@mock.patch.object(il_utils, 'execute', autospec=True)
|
||||
def test_get_bmc_subnet_not_available(self, mocked_execute):
|
||||
mocked_execute.return_value = '', ''
|
||||
self.assertEqual('255.255.255.255', self.hardware.get_bmc_subnet())
|
||||
|
||||
@mock.patch.object(il_utils, 'execute', autospec=True)
|
||||
def test_get_bmc_mac_not_available(self, mocked_execute):
|
||||
mocked_execute.return_value = '', ''
|
||||
|
|
Loading…
Reference in New Issue