Skip to content

Commit

Permalink
Use Blob fields for InvalidRootDirectory
Browse files Browse the repository at this point in the history
A root_scanner code has been adjusted, unit test for non-utf8
filename has been added as well.

OAMG-4306
Depends-On: oamg/leapp#789
  • Loading branch information
fernflower committed Aug 19, 2022
1 parent c7ad39c commit 3d4849f
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 29 deletions.
41 changes: 30 additions & 11 deletions repos/system_upgrade/common/actors/checkrootsymlinks/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from leapp.actors import Actor
from leapp.exceptions import StopActorExecutionError
from leapp.models import Report, RootDirectory
from leapp.tags import IPUWorkflowTag, ChecksPhaseTag
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag


class CheckRootSymlinks(Actor):
Expand All @@ -26,20 +26,39 @@ def process(self):
details={'Problem': 'Did not receive a message with '
'root subdirectories'})
absolute_links = [item for item in rootdir.items if item.target and os.path.isabs(item.target)]
absolute_links_nonutf = [item for item in rootdir.invalid_items if item.target and os.path.isabs(item.target)]
if not absolute_links and not absolute_links_nonutf:
return

if absolute_links:
commands = [' '.join(['ln', '-snf',
os.path.relpath(item.target, '/'),
os.path.join('/', item.name)]) for item in absolute_links]
remediation = [['sh', '-c', ' && '.join(commands)]]
reporting.create_report([
report_fields = [
reporting.Title('Upgrade requires links in root directory to be relative'),
reporting.Summary(
'After rebooting, parts of the upgrade process can fail if symbolic links in / '
'point to absolute paths.\n'
'Please change these links to relative ones.'
),
),
reporting.Severity(reporting.Severity.HIGH),
reporting.Flags([reporting.Flags.INHIBITOR]),
reporting.Remediation(commands=remediation)
])
reporting.Flags([reporting.Flags.INHIBITOR])]

# Generate reports about absolute links presence
rem_commands = []
if absolute_links:
commands = []
for item in absolute_links:
command = ' '.join(['ln',
'-snf',
os.path.relpath(item.target, '/'),
os.path.join('/', item.name)])
commands.append(command)
rem_commands = [['sh', '-c', ' && '.join(commands)]]
# Generate reports about non-utf8 absolute links presence
nonutf_count = len(absolute_links_nonutf)
if nonutf_count > 0:
# for non-utf encoded filenames can't provide a remediation command, so will mention this fact in a hint
rem_hint = ("{} symbolic links point to absolute paths that have non-utf8 encoding and need to be"
" fixed additionally".format(nonutf_count))
report_fields.append(reporting.Remediation(hint=rem_hint, commands=rem_commands))
else:
report_fields.append(reporting.Remediation(commands=rem_commands))

reporting.create_report(report_fields)
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import pytest
import six

from leapp.models import Report, RootDirectory, RootSubdirectory
from leapp.models import InvalidRootSubdirectory, Report, RootDirectory, RootSubdirectory
from leapp.snactor.fixture import current_actor_context


@pytest.mark.parametrize('modified,expected_report', [
({}, False),
({'bin': '/usr/bin'}, True),
({'sbin': 'usr/bin'}, False),
({'sbin': '/usr/sbin'}, True),
({'lib': '/usr/lib', 'lib64': 'usr/lib64'}, True)])
def test_wrong_symlink_inhibitor(current_actor_context, modified, expected_report):
@pytest.mark.parametrize('modified,invalid,expected_report', [
({}, {}, False),
({'bin': '/usr/bin'}, {}, True),
({'sbin': 'usr/bin'}, {}, False),
({'sbin': '/usr/sbin'}, {}, True),
({'lib': '/usr/lib', 'lib64': 'usr/lib64'}, {}, True),
({}, {b'\xc4\xc9\xd2\xc5\xcb\xd4\xcf\xd2\xc9\xd1': b''}, False),
({}, {b'\xc4\xc9\xd2\xc5\xcb\xd4\xcf\xd2\xc9\xd1': b'usr/bin'}, False),
({'lib': '/usr/lib', 'lib64': 'usr/lib64'}, {b'\xc4\xc9\xd2\xc5\xcb\xd4\xcf\xd2\xc9\xd1': b'/usr/lib64'}, True),
({}, {b'\xc4\xc9\xd2\xc5\xcb\xd4\xcf\xd2\xc9\xd1': b'/usr/lib64'}, True)])
def test_wrong_symlink_inhibitor(current_actor_context, modified, invalid, expected_report):
invalid_subdirs = {}
subdirs = {
'bin': 'usr/bin',
'boot': '',
Expand All @@ -33,10 +39,20 @@ def test_wrong_symlink_inhibitor(current_actor_context, modified, expected_repor
'var': ''
}
subdirs.update(modified)
invalid_subdirs.update(invalid)

items = [RootSubdirectory(name=name, target=target) for name, target in subdirs.items()]
current_actor_context.feed(RootDirectory(items=items))
invalid_items = [InvalidRootSubdirectory(name=name, target=target) for name, target in invalid_subdirs.items()]
current_actor_context.feed(RootDirectory(items=items, invalid_items=invalid_items))
current_actor_context.run()
if expected_report:
assert current_actor_context.consume(Report)
report = current_actor_context.consume(Report)
assert report
# Make sure the hint is there in case of non-utf bad symlinks
if invalid_subdirs:
msg = 'symbolic links point to absolute paths that have non-utf8 encoding'
hint = next((rem['context'] for rem in report[0].report['detail']['remediations']
if rem['type'] == 'hint'), None)
assert msg in hint
else:
assert not current_actor_context.consume(Report)
24 changes: 17 additions & 7 deletions repos/system_upgrade/common/actors/rootscanner/actor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import os

import six

from leapp.actors import Actor
from leapp.models import RootDirectory, RootSubdirectory
from leapp.tags import IPUWorkflowTag, FactsPhaseTag
from leapp.models import InvalidRootSubdirectory, RootDirectory, RootSubdirectory
from leapp.tags import FactsPhaseTag, IPUWorkflowTag


class RootScanner(Actor):
Expand All @@ -18,10 +20,18 @@ class RootScanner(Actor):

def process(self):
subdirs = []
for subdir in os.listdir('/'):
path = os.path.join('/', subdir)
invalid_subdirs = []

def _create_a_subdir(subdir_cls, name, path):
if os.path.islink(path):
subdirs.append(RootSubdirectory(name=subdir, target=os.readlink(path)))
return subdir_cls(name=name, target=os.readlink(path))
return subdir_cls(name=name)

for subdir in os.listdir('/'):
# Note(ivasilev) non-utf encoded string will appear as byte strings
if isinstance(subdir, six.binary_type):
invalid_subdirs.append(_create_a_subdir(InvalidRootSubdirectory, subdir, os.path.join(b'/', subdir)))
else:
subdirs.append(RootSubdirectory(name=subdir))
self.produce(RootDirectory(items=subdirs))
subdirs.append(_create_a_subdir(RootSubdirectory, subdir, os.path.join('/', subdir)))

self.produce(RootDirectory(items=subdirs, invalid_items=invalid_subdirs))
12 changes: 11 additions & 1 deletion repos/system_upgrade/common/models/rootdirectory.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from leapp.models import Model, fields
from leapp.models import fields, Model
from leapp.topics import SystemFactsTopic


Expand All @@ -11,6 +11,16 @@ class RootSubdirectory(Model):
target = fields.Nullable(fields.String()) # if it's a link


class InvalidRootSubdirectory(Model):
"""
Representation of a single root subdirectory with non-utf name that is stored as a Blob.
"""
topic = SystemFactsTopic
name = fields.Blob()
target = fields.Nullable(fields.Blob())


class RootDirectory(Model):
topic = SystemFactsTopic
items = fields.List(fields.Model(RootSubdirectory)) # should not be empty
invalid_items = fields.Nullable(fields.List(fields.Model(InvalidRootSubdirectory)))

0 comments on commit 3d4849f

Please sign in to comment.