-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pam_userdb: migrate backend database
pam_userdb module changed its backend database technology from lidb to gdbm for RHEL10. This requires a set of leapp actors to perform the database migration automatically when upgrading to RHEL10: * ScanPamUserDB takes care of scanning the PAM service folder to detect whether pam_userdb is used and the location of the database in use. This information is stored in a model. * CheckPamUserDB checks the databases reported by ScanPamUserDB and prints a report about them. * ConvertPamUserDB checks the databases reported by ScanPamUserDB and converts them to GDBM format. * RemoveOldPamUserDB checks the databases reported by ScanPamUserDB and removes them. All these actors include unit-tests. Finally, there's also a spec file change to add `libdb-utils` dependency as it is required to convert pam_userdb databases from BerkeleyDB to GDBM. Signed-off-by: Iker Pedrosa <[email protected]>
- Loading branch information
1 parent
88e13fb
commit 658700d
Showing
17 changed files
with
359 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
repos/system_upgrade/el9toel10/actors/pamuserdb/checkpamuserdb/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import checkpamuserdb | ||
from leapp.models import PamUserDbLocation, Report | ||
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag | ||
|
||
|
||
class CheckPamUserDb(Actor): | ||
""" | ||
Create report with the location of pam_userdb databases | ||
""" | ||
|
||
name = 'check_pam_user_db' | ||
consumes = (PamUserDbLocation,) | ||
produces = (Report,) | ||
tags = (ChecksPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
checkpamuserdb.process() |
28 changes: 28 additions & 0 deletions
28
repos/system_upgrade/el9toel10/actors/pamuserdb/checkpamuserdb/libraries/checkpamuserdb.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from leapp import reporting | ||
from leapp.exceptions import StopActorExecutionError | ||
from leapp.libraries.stdlib import api | ||
from leapp.models import PamUserDbLocation | ||
|
||
FMT_LIST_SEPARATOR = "\n - " | ||
|
||
|
||
def process(): | ||
msg = next(api.consume(PamUserDbLocation), None) | ||
if not msg: | ||
raise StopActorExecutionError('Expected PamUserDbLocation, but got None') | ||
|
||
if msg.locations: | ||
reporting.create_report([ | ||
reporting.Title('pam_userdb databases will be converted to GDBM'), | ||
reporting.Summary( | ||
'On RHEL 10, GDMB is used by pam_userdb as it\'s backend database,' | ||
' replacing BerkeleyDB. Existing pam_userdb databases will be' | ||
' converted to GDBM. The following databases will be converted:' | ||
'{sep}{locations}'.format(sep=FMT_LIST_SEPARATOR, locations=FMT_LIST_SEPARATOR.join(msg.locations))), | ||
reporting.Severity(reporting.Severity.INFO), | ||
reporting.Groups([reporting.Groups.SECURITY, reporting.Groups.AUTHENTICATION]) | ||
]) | ||
else: | ||
api.current_logger().debug( | ||
'No pam_userdb databases were located, thus nothing will be converted' | ||
) |
43 changes: 43 additions & 0 deletions
43
repos/system_upgrade/el9toel10/actors/pamuserdb/checkpamuserdb/tests/test_checkpamuserdb.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import pytest | ||
|
||
from leapp import reporting | ||
from leapp.exceptions import StopActorExecutionError | ||
from leapp.libraries.actor import checkpamuserdb | ||
from leapp.libraries.common.testutils import create_report_mocked, logger_mocked | ||
from leapp.libraries.stdlib import api | ||
from leapp.models import PamUserDbLocation | ||
|
||
|
||
def test_process_no_msg(monkeypatch): | ||
def consume_mocked(*args, **kwargs): | ||
yield None | ||
|
||
monkeypatch.setattr(api, 'consume', consume_mocked) | ||
|
||
with pytest.raises(StopActorExecutionError): | ||
checkpamuserdb.process() | ||
|
||
|
||
def test_process_no_location(monkeypatch): | ||
def consume_mocked(*args, **kwargs): | ||
yield PamUserDbLocation(locations=[]) | ||
|
||
monkeypatch.setattr(api, 'current_logger', logger_mocked()) | ||
monkeypatch.setattr(api, 'consume', consume_mocked) | ||
|
||
checkpamuserdb.process() | ||
assert ( | ||
'No pam_userdb databases were located, thus nothing will be converted' | ||
in api.current_logger.dbgmsg | ||
) | ||
|
||
|
||
def test_process_locations(monkeypatch): | ||
def consume_mocked(*args, **kwargs): | ||
yield PamUserDbLocation(locations=['/tmp/db1', '/tmp/db2']) | ||
|
||
monkeypatch.setattr(reporting, "create_report", create_report_mocked()) | ||
monkeypatch.setattr(api, 'consume', consume_mocked) | ||
|
||
checkpamuserdb.process() | ||
assert reporting.create_report.called == 1 |
18 changes: 18 additions & 0 deletions
18
repos/system_upgrade/el9toel10/actors/pamuserdb/convertpamuserdb/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import convertpamuserdb | ||
from leapp.models import PamUserDbLocation | ||
from leapp.tags import IPUWorkflowTag, PreparationPhaseTag | ||
|
||
|
||
class ConvertPamUserDb(Actor): | ||
""" | ||
Convert the pam_userdb databases to GDBM | ||
""" | ||
|
||
name = 'convert_pam_user_db' | ||
consumes = (PamUserDbLocation,) | ||
produces = () | ||
tags = (PreparationPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
convertpamuserdb.process() |
27 changes: 27 additions & 0 deletions
27
.../system_upgrade/el9toel10/actors/pamuserdb/convertpamuserdb/libraries/convertpamuserdb.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from leapp.exceptions import StopActorExecutionError | ||
from leapp.libraries.stdlib import api, CalledProcessError, run | ||
from leapp.models import PamUserDbLocation | ||
|
||
|
||
def _convert_db(db_path): | ||
cmd = ['db_converter', '--src', f'{db_path}.db', '--dest', f'{db_path}.gdbm'] | ||
try: | ||
run(cmd) | ||
except (CalledProcessError, OSError) as e: | ||
# As the db_converter does not remove the original DB after conversion or upon failure, | ||
# interrupt the upgrade, keeping the original DBs. | ||
# If all DBs are successfully converted, the leftover DBs are removed in the removeoldpamuserdb actor. | ||
raise StopActorExecutionError( | ||
'Cannot convert pam_userdb database.', | ||
details={'details': '{}: {}'.format(str(e), e.stderr)} | ||
) | ||
|
||
|
||
def process(): | ||
msg = next(api.consume(PamUserDbLocation), None) | ||
if not msg: | ||
raise StopActorExecutionError('Expected PamUserDbLocation, but got None') | ||
|
||
if msg.locations: | ||
for location in msg.locations: | ||
_convert_db(location) |
39 changes: 39 additions & 0 deletions
39
...system_upgrade/el9toel10/actors/pamuserdb/convertpamuserdb/tests/test_convertpamuserdb.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import os | ||
|
||
import pytest | ||
|
||
from leapp.exceptions import StopActorExecutionError | ||
from leapp.libraries.actor import convertpamuserdb | ||
from leapp.libraries.common.testutils import logger_mocked | ||
from leapp.libraries.stdlib import api, CalledProcessError | ||
|
||
CUR_DIR = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
|
||
def test_convert_db_success(monkeypatch): | ||
location = os.path.join(CUR_DIR, '/files/db1') | ||
|
||
def run_mocked(cmd, **kwargs): | ||
assert cmd == ['db_converter', '--src', f'{location}.db', '--dest', f'{location}.gdbm'] | ||
|
||
monkeypatch.setattr(api, 'current_logger', logger_mocked()) | ||
monkeypatch.setattr(convertpamuserdb, 'run', run_mocked) | ||
convertpamuserdb._convert_db(location) | ||
assert len(api.current_logger.errmsg) == 0 | ||
|
||
|
||
def test_convert_db_failure(monkeypatch): | ||
location = os.path.join(CUR_DIR, '/files/db1') | ||
|
||
def run_mocked(cmd, **kwargs): | ||
raise CalledProcessError( | ||
message='A Leapp Command Error occurred.', | ||
command=cmd, | ||
result={'exit_code': 1} | ||
) | ||
|
||
monkeypatch.setattr(api, 'current_logger', logger_mocked()) | ||
monkeypatch.setattr(convertpamuserdb, 'run', run_mocked) | ||
with pytest.raises(StopActorExecutionError) as err: | ||
convertpamuserdb._convert_db(location) | ||
assert str(err.value) == 'Cannot convert pam_userdb database.' |
18 changes: 18 additions & 0 deletions
18
repos/system_upgrade/el9toel10/actors/pamuserdb/removeoldpamuserdb/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import removeoldpamuserdb | ||
from leapp.models import PamUserDbLocation | ||
from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag | ||
|
||
|
||
class RemoveOldPamUserDb(Actor): | ||
""" | ||
Remove old pam_userdb databases | ||
""" | ||
|
||
name = 'remove_old_pam_user_db' | ||
consumes = (PamUserDbLocation,) | ||
produces = () | ||
tags = (ApplicationsPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
removeoldpamuserdb.process() |
25 changes: 25 additions & 0 deletions
25
...tem_upgrade/el9toel10/actors/pamuserdb/removeoldpamuserdb/libraries/removeoldpamuserdb.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from leapp.exceptions import StopActorExecutionError | ||
from leapp.libraries.stdlib import api, CalledProcessError, run | ||
from leapp.models import PamUserDbLocation | ||
|
||
|
||
def _remove_db(db_path): | ||
cmd = ['rm', '-f', f'{db_path}.db'] | ||
try: | ||
run(cmd) | ||
except (CalledProcessError, OSError) as e: | ||
api.current_logger().error( | ||
'Failed to remove {}.db: {}'.format( | ||
db_path, e | ||
) | ||
) | ||
|
||
|
||
def process(): | ||
msg = next(api.consume(PamUserDbLocation), None) | ||
if not msg: | ||
raise StopActorExecutionError('Expected PamUserDbLocation, but got None') | ||
|
||
if msg.locations: | ||
for location in msg.locations: | ||
_remove_db(location) |
38 changes: 38 additions & 0 deletions
38
...em_upgrade/el9toel10/actors/pamuserdb/removeoldpamuserdb/tests/test_removeoldpamuserdb.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import os | ||
|
||
from leapp.libraries.actor import removeoldpamuserdb | ||
from leapp.libraries.common.testutils import logger_mocked | ||
from leapp.libraries.stdlib import api, CalledProcessError | ||
|
||
CUR_DIR = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
|
||
def test_remove_db_success(monkeypatch): | ||
location = os.path.join(CUR_DIR, '/files/db1') | ||
|
||
def run_mocked(cmd, **kwargs): | ||
assert cmd == ['rm', '-f', f'{location}.db'] | ||
|
||
monkeypatch.setattr(api, 'current_logger', logger_mocked()) | ||
monkeypatch.setattr(removeoldpamuserdb, 'run', run_mocked) | ||
removeoldpamuserdb._remove_db(location) | ||
assert len(api.current_logger.errmsg) == 0 | ||
|
||
|
||
def test_remove_db_failure(monkeypatch): | ||
location = os.path.join(CUR_DIR, '/files/db1') | ||
|
||
def run_mocked(cmd, **kwargs): | ||
raise CalledProcessError( | ||
message='A Leapp Command Error occurred.', | ||
command=cmd, | ||
result={'exit_code': 1} | ||
) | ||
|
||
monkeypatch.setattr(api, 'current_logger', logger_mocked()) | ||
monkeypatch.setattr(removeoldpamuserdb, 'run', run_mocked) | ||
removeoldpamuserdb._remove_db(location) | ||
assert ( | ||
'Failed to remove /files/db1.db' | ||
not in api.current_logger.errmsg | ||
) |
18 changes: 18 additions & 0 deletions
18
repos/system_upgrade/el9toel10/actors/pamuserdb/scanpamuserdb/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import scanpamuserdb | ||
from leapp.models import PamUserDbLocation | ||
from leapp.tags import FactsPhaseTag, IPUWorkflowTag | ||
|
||
|
||
class ScanPamUserDb(Actor): | ||
""" | ||
Scan the PAM service folder for the location of pam_userdb databases | ||
""" | ||
|
||
name = 'scan_pam_user_db' | ||
consumes = () | ||
produces = (PamUserDbLocation,) | ||
tags = (FactsPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
self.produce(scanpamuserdb.parse_pam_config_folder('/etc/pam.d/')) |
29 changes: 29 additions & 0 deletions
29
repos/system_upgrade/el9toel10/actors/pamuserdb/scanpamuserdb/libraries/scanpamuserdb.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import os | ||
import re | ||
|
||
from leapp.models import PamUserDbLocation | ||
|
||
|
||
def _parse_pam_config_file(conf_file): | ||
with open(conf_file, 'r') as file: | ||
for line in file: | ||
if 'pam_userdb' in line: | ||
match = re.search(r'db=(\S+)', line) | ||
if match: | ||
return match.group(1) | ||
|
||
return None | ||
|
||
|
||
def parse_pam_config_folder(conf_folder): | ||
locations = set() | ||
|
||
for file_name in os.listdir(conf_folder): | ||
file_path = os.path.join(conf_folder, file_name) | ||
|
||
if os.path.isfile(file_path): | ||
location = _parse_pam_config_file(file_path) | ||
if location is not None: | ||
locations.add(location) | ||
|
||
return PamUserDbLocation(locations=list(locations)) |
1 change: 1 addition & 0 deletions
1
repos/system_upgrade/el9toel10/actors/pamuserdb/scanpamuserdb/tests/files/pam_userdb_basic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
auth required pam_userdb.so db=/tmp/db1 |
9 changes: 9 additions & 0 deletions
9
...s/system_upgrade/el9toel10/actors/pamuserdb/scanpamuserdb/tests/files/pam_userdb_complete
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
auth required pam_env.so | ||
auth required pam_faildelay.so delay=2000000 | ||
auth sufficient pam_fprintd.so | ||
auth [default=1 ignore=ignore success=ok] pam_usertype.so isregular | ||
auth [default=1 ignore=ignore success=ok] pam_localuser.so | ||
auth required pam_userdb.so db=/tmp/db2 | ||
auth [default=1 ignore=ignore success=ok] pam_usertype.so isregular | ||
auth sufficient pam_sss.so forward_pass | ||
auth required pam_deny.so |
1 change: 1 addition & 0 deletions
1
repos/system_upgrade/el9toel10/actors/pamuserdb/scanpamuserdb/tests/files/pam_userdb_missing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
auth sufficient pam_unix.so nullok |
27 changes: 27 additions & 0 deletions
27
repos/system_upgrade/el9toel10/actors/pamuserdb/scanpamuserdb/tests/test_scanpamuserdb.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import os | ||
|
||
import pytest | ||
|
||
from leapp.libraries.actor import scanpamuserdb | ||
|
||
CUR_DIR = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"inp,exp_out", | ||
[ | ||
("files/pam_userdb_missing", None), | ||
("files/pam_userdb_basic", "/tmp/db1"), | ||
("files/pam_userdb_complete", "/tmp/db2"), | ||
], | ||
) | ||
def test_parse_pam_config_file(inp, exp_out): | ||
file = scanpamuserdb._parse_pam_config_file(os.path.join(CUR_DIR, inp)) | ||
assert file == exp_out | ||
|
||
|
||
def test_parse_pam_config_folder(): | ||
msg = scanpamuserdb.parse_pam_config_folder(os.path.join(CUR_DIR, "files/")) | ||
assert len(msg.locations) == 2 | ||
assert "/tmp/db1" in msg.locations | ||
assert "/tmp/db2" in msg.locations |
14 changes: 14 additions & 0 deletions
14
repos/system_upgrade/el9toel10/models/pamuserdblocation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from leapp.models import fields, Model | ||
from leapp.topics import SystemInfoTopic | ||
|
||
|
||
class PamUserDbLocation(Model): | ||
""" | ||
Provides a list of all database files for pam_userdb | ||
""" | ||
topic = SystemInfoTopic | ||
|
||
locations = fields.List(fields.String(), default=[]) | ||
""" | ||
The list with the full path to the database files. | ||
""" |