Add clean step 'erase_pstore'
Add an automatic clean step to clean the Linux kernel's pstore. The step is disabled by default. Story: #2008317 Task: #41214 Change-Id: Ie1a42dfff4c7e1c7abeaf39feca956bb9e2ea497
This commit is contained in:
parent
1f590ea382
commit
92e26b01e9
@ -35,6 +35,9 @@ Clean steps
|
|||||||
``deploy.erase_devices_metadata``
|
``deploy.erase_devices_metadata``
|
||||||
Erases partition tables from all recognized disk devices. Can be used as
|
Erases partition tables from all recognized disk devices. Can be used as
|
||||||
an alternative to the much longer ``erase_devices`` step.
|
an alternative to the much longer ``erase_devices`` step.
|
||||||
|
``deploy.erase_pstore``
|
||||||
|
Erases entries from pstore, the kernel's oops/panic logger. Disabled by
|
||||||
|
default. Can be enabled via priority overrides.
|
||||||
``raid.create_configuration``
|
``raid.create_configuration``
|
||||||
Create a RAID configuration. This step belongs to the ``raid`` interface
|
Create a RAID configuration. This step belongs to the ``raid`` interface
|
||||||
and must be used through the :ironic-doc:`ironic RAID feature
|
and must be used through the :ironic-doc:`ironic RAID feature
|
||||||
|
@ -22,6 +22,7 @@ from multiprocessing.pool import ThreadPool
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
|
import shutil
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from ironic_lib import disk_utils
|
from ironic_lib import disk_utils
|
||||||
@ -1314,6 +1315,37 @@ class GenericHardwareManager(HardwareManager):
|
|||||||
for k, v in erase_errors.items()]))
|
for k, v in erase_errors.items()]))
|
||||||
raise errors.BlockDeviceEraseError(excpt_msg)
|
raise errors.BlockDeviceEraseError(excpt_msg)
|
||||||
|
|
||||||
|
def _find_pstore_mount_point(self):
|
||||||
|
"""Find the pstore mount point by scanning /proc/mounts.
|
||||||
|
|
||||||
|
:returns: The pstore mount if existing, none otherwise.
|
||||||
|
"""
|
||||||
|
with open("/proc/mounts", "r") as mounts:
|
||||||
|
for line in mounts:
|
||||||
|
# /proc/mounts format is: "device mountpoint fstype ..."
|
||||||
|
m = re.match(r'^pstore (\S+) pstore', line)
|
||||||
|
if m:
|
||||||
|
return m.group(1)
|
||||||
|
|
||||||
|
def erase_pstore(self, node, ports):
|
||||||
|
"""Attempt to erase the kernel pstore.
|
||||||
|
|
||||||
|
:param node: Ironic node object
|
||||||
|
:param ports: list of Ironic port objects
|
||||||
|
"""
|
||||||
|
pstore_path = self._find_pstore_mount_point()
|
||||||
|
if not pstore_path:
|
||||||
|
LOG.debug("No pstore found")
|
||||||
|
return
|
||||||
|
|
||||||
|
LOG.info("Cleaning up pstore in %s", pstore_path)
|
||||||
|
for file in os.listdir(pstore_path):
|
||||||
|
filepath = os.path.join(pstore_path, file)
|
||||||
|
try:
|
||||||
|
shutil.rmtree(filepath)
|
||||||
|
except OSError:
|
||||||
|
os.remove(filepath)
|
||||||
|
|
||||||
def _shred_block_device(self, node, block_device):
|
def _shred_block_device(self, node, block_device):
|
||||||
"""Erase a block device using shred.
|
"""Erase a block device using shred.
|
||||||
|
|
||||||
@ -1680,6 +1712,13 @@ class GenericHardwareManager(HardwareManager):
|
|||||||
'reboot_requested': False,
|
'reboot_requested': False,
|
||||||
'abortable': True
|
'abortable': True
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'step': 'erase_pstore',
|
||||||
|
'priority': 0,
|
||||||
|
'interface': 'deploy',
|
||||||
|
'reboot_requested': False,
|
||||||
|
'abortable': True
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'step': 'delete_configuration',
|
'step': 'delete_configuration',
|
||||||
'priority': 0,
|
'priority': 0,
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import time
|
import time
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
@ -859,6 +860,24 @@ MDADM_EXAMINE_OUTPUT_NON_MEMBER = ("""/dev/sdz1:
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
PROC_MOUNTS_OUTPUT = ("""
|
||||||
|
debugfs /sys/kernel/debug debugfs rw,relatime 0 0
|
||||||
|
/dev/sda2 / ext4 rw,relatime,errors=remount-ro 0 0
|
||||||
|
tmpfs /run/user/1000 tmpfs rw,nosuid,nodev,relatime 0 0
|
||||||
|
pstore /sys/fs/pstore pstore rw,nosuid,nodev,noexec,relatime 0 0
|
||||||
|
/dev/loop19 /snap/core/10126 squashfs ro,nodev,relatime 0 0
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
PROC_MOUNTS_OUTPUT_NO_PSTORE = ("""
|
||||||
|
debugfs /sys/kernel/debug debugfs rw,relatime 0 0
|
||||||
|
/dev/sda2 / ext4 rw,relatime,errors=remount-ro 0 0
|
||||||
|
tmpfs /run/user/1000 tmpfs rw,nosuid,nodev,relatime 0 0
|
||||||
|
pstore /sys/fs/pstore qstore rw,nosuid,nodev,noexec,relatime 0 0
|
||||||
|
/dev/loop19 /snap/core/10126 squashfs ro,nodev,relatime 0 0
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
class FakeHardwareManager(hardware.GenericHardwareManager):
|
class FakeHardwareManager(hardware.GenericHardwareManager):
|
||||||
def __init__(self, hardware_support):
|
def __init__(self, hardware_support):
|
||||||
self._hardware_support = hardware_support
|
self._hardware_support = hardware_support
|
||||||
@ -921,6 +940,13 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
|||||||
'reboot_requested': False,
|
'reboot_requested': False,
|
||||||
'abortable': True
|
'abortable': True
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'step': 'erase_pstore',
|
||||||
|
'priority': 0,
|
||||||
|
'interface': 'deploy',
|
||||||
|
'reboot_requested': False,
|
||||||
|
'abortable': True
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'step': 'delete_configuration',
|
'step': 'delete_configuration',
|
||||||
'priority': 0,
|
'priority': 0,
|
||||||
@ -2631,6 +2657,44 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
|||||||
test_security_erase_option(
|
test_security_erase_option(
|
||||||
self, False, '--security-erase')
|
self, False, '--security-erase')
|
||||||
|
|
||||||
|
def test__find_pstore_mount_point(self):
|
||||||
|
with mock.patch('builtins.open',
|
||||||
|
mock.mock_open(),
|
||||||
|
create=True) as mocked_open:
|
||||||
|
mocked_open.return_value.__iter__ = \
|
||||||
|
lambda self: iter(PROC_MOUNTS_OUTPUT.splitlines())
|
||||||
|
|
||||||
|
self.assertEqual(self.hardware._find_pstore_mount_point(),
|
||||||
|
"/sys/fs/pstore")
|
||||||
|
mocked_open.assert_called_once_with('/proc/mounts', 'r')
|
||||||
|
|
||||||
|
def test__find_pstore_mount_point_no_pstore(self):
|
||||||
|
with mock.patch('builtins.open',
|
||||||
|
mock.mock_open(),
|
||||||
|
create=True) as mocked_open:
|
||||||
|
mocked_open.return_value.__iter__.return_value = \
|
||||||
|
PROC_MOUNTS_OUTPUT_NO_PSTORE.splitlines()
|
||||||
|
self.assertIsNone(self.hardware._find_pstore_mount_point())
|
||||||
|
mocked_open.assert_called_once_with('/proc/mounts', 'r')
|
||||||
|
|
||||||
|
@mock.patch('os.listdir', autospec=True)
|
||||||
|
@mock.patch.object(shutil, 'rmtree', autospec=True)
|
||||||
|
@mock.patch.object(hardware.GenericHardwareManager,
|
||||||
|
'_find_pstore_mount_point', autospec=True)
|
||||||
|
def test_erase_pstore(self, mocked_find_pstore, mocked_rmtree,
|
||||||
|
mocked_listdir):
|
||||||
|
mocked_find_pstore.return_value = '/sys/fs/pstore'
|
||||||
|
pstore_entries = ['dmesg-erst-663482778',
|
||||||
|
'dmesg-erst-663482779']
|
||||||
|
mocked_listdir.return_value = pstore_entries
|
||||||
|
self.hardware.erase_pstore(self.node, [])
|
||||||
|
mocked_listdir.assert_called_once()
|
||||||
|
self.assertEqual(mocked_rmtree.call_count,
|
||||||
|
len(pstore_entries))
|
||||||
|
mocked_rmtree.assert_has_calls([
|
||||||
|
mock.call('/sys/fs/pstore/' + arg) for arg in pstore_entries
|
||||||
|
])
|
||||||
|
|
||||||
@mock.patch.object(utils, 'execute', autospec=True)
|
@mock.patch.object(utils, 'execute', autospec=True)
|
||||||
@mock.patch.object(hardware.GenericHardwareManager,
|
@mock.patch.object(hardware.GenericHardwareManager,
|
||||||
'_is_virtual_media_device', autospec=True)
|
'_is_virtual_media_device', autospec=True)
|
||||||
|
11
releasenotes/notes/add_erase_pstore-b109c58ed8f5d351.yaml
Normal file
11
releasenotes/notes/add_erase_pstore-b109c58ed8f5d351.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds a clean step to erase the Linux kernel's pstore. The step is disabled
|
||||||
|
by default.
|
||||||
|
security:
|
||||||
|
- |
|
||||||
|
If enabled, the new clean step 'erase_pstore' removes all pstore entries
|
||||||
|
(the oops/panic logs from a failing kernel) upon cleaning. This is to
|
||||||
|
reduce the risk that potentially sensitive data is preserved across
|
||||||
|
instantiations (and therefore different users) of a bare metal node.
|
Loading…
Reference in New Issue
Block a user