Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class CheckMountOptions(Actor):

Checks performed:
- /var is mounted with the noexec option
- any fstab entry uses the _netdev mount option
"""
name = "check_mount_options"
consumes = (StorageInfo,)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from leapp import reporting
from leapp.libraries.common.config import get_env
from leapp.libraries.stdlib import api
from leapp.models import StorageInfo

Expand Down Expand Up @@ -70,6 +71,56 @@ def check_noexec_on_var(storage_info):
return


def check_netdev_mounts(storage_info):
"""Check for fstab entries with the _netdev mount option without nofail.

Entries combining _netdev with nofail are skipped: nofail tells systemd not
to fail the boot if the mount fails, so the upgrade can proceed even though
the network mount itself will not come up before the first reboot.
"""
if get_env('LEAPP_DEVEL_INITRAM_NETWORK', None):
return

netdev_entries = [
entry for entry in storage_info.fstab
if '_netdev' in entry.fs_mntops.split(',')
and 'nofail' not in entry.fs_mntops.split(',')
]

if not netdev_entries:
return

entries_str = '\n'.join(
'- {} (mounted at {})'.format(entry.fs_spec, entry.fs_file)
for entry in netdev_entries
)

reporting.create_report([
reporting.Title(
'Detected _netdev mount option in /etc/fstab, preventing a successful in-place upgrade.'
),
reporting.Summary(
'Leapp detected one or more entries in /etc/fstab using the _netdev mount option '
'without nofail:\n{}\n\n'
'During the in-place upgrade, the system is disconnected from the network before '
'the first reboot. Entries with the _netdev option cannot be mounted at that point, '
'which causes the upgrade to fail.'.format(entries_str)
),
reporting.Remediation(
hint=(
'Either remove the _netdev option from the affected /etc/fstab entries before '
'proceeding with the upgrade (and add it back afterwards if needed), or add the '
'nofail option so the boot does not fail when the network mount is unavailable.'
)
),
reporting.RelatedResource('file', '/etc/fstab'),
reporting.Severity(reporting.Severity.HIGH),
reporting.Groups([reporting.Groups.FILESYSTEM, reporting.Groups.NETWORK]),
reporting.Groups([reporting.Groups.INHIBITOR]),
])


def check_mount_options():
for storage_info in api.consume(StorageInfo):
check_noexec_on_var(storage_info)
check_netdev_mounts(storage_info)
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest

from leapp import reporting
from leapp.libraries.actor.checkmountoptions import check_mount_options
from leapp.libraries.actor.checkmountoptions import check_mount_options, check_netdev_mounts
from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked
from leapp.libraries.stdlib import api
from leapp.models import FstabEntry, MountEntry, StorageInfo
Expand Down Expand Up @@ -59,3 +59,42 @@ def test_var_mounted_with_noexec_is_detected(monkeypatch, fstab_entries, mounts,
check_mount_options()

assert bool(created_reports.called) == should_inhibit


def _make_fstab_entry(fs_spec, fs_file, fs_mntops, fs_vfstype='ext4'):
return FstabEntry(fs_spec=fs_spec, fs_file=fs_file, fs_vfstype=fs_vfstype,
fs_mntops=fs_mntops, fs_freq='0', fs_passno='0')


@pytest.mark.parametrize(
('fstab_mntops', 'initram_network_envar', 'should_inhibit'),
[
('_netdev,defaults', None, True),
('defaults,_netdev', None, True),
('_netdev', None, True),
('defaults', None, False),
('netdev,defaults', None, False),
('_netdev,defaults', '1', False),
('_netdev,nofail', None, False),
('nofail,_netdev,defaults', None, False),
('_netdev,nofail,defaults', None, False),
]
)
def test_netdev_in_fstab_is_detected(monkeypatch, fstab_mntops, initram_network_envar, should_inhibit):
fstab_entries = [
_make_fstab_entry('UUID=abc123', '/var/lib/psa/dumps', fstab_mntops),
_make_fstab_entry('/dev/sda1', '/', 'defaults'),
]
storage_info = StorageInfo(fstab=fstab_entries)

envars = {'LEAPP_DEVEL_INITRAM_NETWORK': initram_network_envar} if initram_network_envar else {}
created_reports = create_report_mocked()
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(envars=envars))
monkeypatch.setattr(reporting, 'create_report', created_reports)

check_netdev_mounts(storage_info)

assert bool(created_reports.called) == should_inhibit
if should_inhibit:
assert '_netdev' in created_reports.report_fields['title']
assert 'UUID=abc123' in created_reports.report_fields['summary']
Loading