Skip to content

Commit 332fe36

Browse files
jochapmapre-commit-ci[bot]abadger
authored
[RHELC-1099] Move application lock into main. (#904)
* Move application lock into main. * Remove an unused import. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Prevent backtrace when non-root user runs --help. * Update convert2rhel/main.py Add a comment explaining why we don't log a message. Co-authored-by: Toshio Kuratomi <a.badger@gmail.com> * Update convert2rhel/main.py Clarify comment on main(). Co-authored-by: Toshio Kuratomi <a.badger@gmail.com> * Update convert2rhel/unit_tests/initialize_test.py Fix imports. Co-authored-by: Toshio Kuratomi <a.badger@gmail.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Apply changes suggested in review. * Fix an import problem. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Toshio Kuratomi <a.badger@gmail.com>
1 parent 5488aa6 commit 332fe36

File tree

4 files changed

+70
-57
lines changed

4 files changed

+70
-57
lines changed

convert2rhel/initialize.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717

1818
import logging
1919
import os
20-
import sys
2120

22-
from convert2rhel import applock, i18n, utils
21+
from convert2rhel import i18n
2322

2423

2524
def disable_root_logger():
@@ -66,26 +65,16 @@ def set_locale():
6665
def run():
6766
"""Wrapper around the main function.
6867
69-
This function is intended to initialize all early code and function calls
70-
before any other main imports.
68+
This function is needed to initialize early code and function calls
69+
that have to be done before certain modules (which are imported by
70+
main) are imported.
7171
"""
7272
# prepare environment
7373
set_locale()
7474

7575
# Initialize logging to stop duplicate messages.
7676
disable_root_logger()
7777

78-
# Make sure we're being run by root
79-
utils.require_root()
80-
8178
from convert2rhel import main
8279

83-
retval = 0
84-
try:
85-
with applock.ApplicationLock("convert2rhel"):
86-
retval = main.main()
87-
except applock.ApplicationLockedError:
88-
retval = 1
89-
sys.stderr.write("Another copy of convert2rhel is running.\n")
90-
sys.stderr.write("\nNo changes were made to the system.\n")
91-
sys.exit(retval)
80+
return main.main()

convert2rhel/main.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717

1818
import logging
1919
import os
20+
import sys
2021

21-
from convert2rhel import actions, backup, breadcrumbs, checks, grub
22+
from convert2rhel import actions, applock, backup, breadcrumbs, checks, grub
2223
from convert2rhel import logger as logger_module
2324
from convert2rhel import pkghandler, pkgmanager, redhatrelease, repo, subscription, systeminfo, toolopts, utils
2425
from convert2rhel.actions import level_for_raw_action_data, report
@@ -63,16 +64,39 @@ def initialize_logger(log_name, log_dir):
6364

6465

6566
def main():
66-
"""Perform all steps for the entire conversion process."""
67+
"""
68+
Wrapper around the main entrypoint.
69+
70+
Performs everything necessary to set up before starting the actual
71+
conversion process itself, then calls main_locked(), protected by
72+
the application lock, to do the conversion process.
73+
"""
6774

6875
process_phase = ConversionPhase.INIT
6976

77+
# Make sure we're being run by root
78+
utils.require_root()
79+
7080
# initialize logging
7181
initialize_logger("convert2rhel.log", logger_module.LOG_DIR)
7282

7383
# handle command line arguments
7484
toolopts.CLI()
7585

86+
try:
87+
with applock.ApplicationLock("convert2rhel"):
88+
return main_locked(process_phase)
89+
except applock.ApplicationLockedError:
90+
# We have not rotated the log files at this point because main.initialize_logger()
91+
# has not yet been called. So we use sys.stderr.write() instead of loggerinst.error()
92+
sys.stderr.write("Another copy of convert2rhel is running.\n")
93+
sys.stderr.write("\nNo changes were made to the system.\n")
94+
return 1
95+
96+
97+
def main_locked(process_phase):
98+
"""Perform all steps for the entire conversion process."""
99+
76100
pre_conversion_results = None
77101
try:
78102
process_phase = ConversionPhase.POST_CLI

convert2rhel/unit_tests/initialize_test.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,8 @@
1818
import os
1919

2020
import pytest
21-
import six
2221

23-
from convert2rhel import applock, initialize, main, utils
24-
25-
26-
six.add_move(six.MovedModule("mock", "mock", "unittest.mock"))
27-
from six.moves import mock
22+
from convert2rhel import applock, initialize, main
2823

2924

3025
@pytest.mark.parametrize(
@@ -35,25 +30,6 @@
3530
),
3631
)
3732
def test_run(monkeypatch, exit_code, tmp_path):
38-
require_root_mock = mock.Mock()
39-
monkeypatch.setattr(utils, "require_root", require_root_mock)
4033
monkeypatch.setattr(main, "main", value=lambda: exit_code)
4134
monkeypatch.setattr(applock, "_DEFAULT_LOCK_DIR", str(tmp_path))
42-
with pytest.raises(SystemExit):
43-
initialize.run()
44-
assert require_root_mock.call_count == 1
45-
46-
47-
def test_locked(monkeypatch, tmp_path, capsys):
48-
require_root_mock = mock.Mock()
49-
monkeypatch.setattr(utils, "require_root", require_root_mock)
50-
monkeypatch.setattr(applock, "_DEFAULT_LOCK_DIR", str(tmp_path))
51-
pidfile = os.path.join(str(tmp_path), "convert2rhel.pid")
52-
with open(pidfile, "w") as f:
53-
f.write(str(os.getpid()) + "\n")
54-
with pytest.raises(SystemExit):
55-
initialize.run()
56-
captured = capsys.readouterr()
57-
assert "Another copy of convert2rhel" in captured.err
58-
os.unlink(pidfile)
59-
assert require_root_mock.call_count == 1
35+
assert initialize.run() == exit_code

convert2rhel/unit_tests/main_test.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
six.add_move(six.MovedModule("mock", "mock", "unittest.mock"))
2828
from six.moves import mock
2929

30-
from convert2rhel import actions, backup, cert, checks, grub
30+
from convert2rhel import actions, applock, backup, cert, checks, grub
3131
from convert2rhel import logger as logger_module
3232
from convert2rhel import main, pkghandler, pkgmanager, redhatrelease, repo, subscription, toolopts, unit_tests, utils
3333
from convert2rhel.actions import report
@@ -201,7 +201,8 @@ def test_post_ponr_conversion(monkeypatch):
201201
assert lock_releasever_in_rhel_repositories_mock.call_count == 1
202202

203203

204-
def test_main(monkeypatch):
204+
def test_main(monkeypatch, tmp_path):
205+
require_root_mock = mock.Mock()
205206
initialize_logger_mock = mock.Mock()
206207
toolopts_cli_mock = mock.Mock()
207208
show_eula_mock = mock.Mock()
@@ -225,6 +226,8 @@ def test_main(monkeypatch):
225226
update_rhsm_custom_facts_mock = mock.Mock()
226227
summary_as_json_mock = mock.Mock()
227228

229+
monkeypatch.setattr(applock, "_DEFAULT_LOCK_DIR", str(tmp_path))
230+
monkeypatch.setattr(utils, "require_root", require_root_mock)
228231
monkeypatch.setattr(main, "initialize_logger", initialize_logger_mock)
229232
monkeypatch.setattr(toolopts, "CLI", toolopts_cli_mock)
230233
monkeypatch.setattr(main, "show_eula", show_eula_mock)
@@ -249,6 +252,7 @@ def test_main(monkeypatch):
249252
monkeypatch.setattr(report, "summary_as_json", summary_as_json_mock)
250253

251254
assert main.main() == 0
255+
assert require_root_mock.call_count == 1
252256
assert initialize_logger_mock.call_count == 1
253257
assert toolopts_cli_mock.call_count == 1
254258
assert show_eula_mock.call_count == 1
@@ -271,28 +275,33 @@ def test_main(monkeypatch):
271275
assert summary_as_json_mock.call_count == 1
272276

273277

274-
def test_main_rollback_post_cli_phase(monkeypatch, caplog):
278+
def test_main_rollback_post_cli_phase(monkeypatch, caplog, tmp_path):
279+
require_root_mock = mock.Mock()
275280
initialize_logger_mock = mock.Mock()
276281
toolopts_cli_mock = mock.Mock()
277282
show_eula_mock = mock.Mock(side_effect=Exception)
278283

279284
# Mock the rollback calls
280285
finish_collection_mock = mock.Mock()
281286

287+
monkeypatch.setattr(applock, "_DEFAULT_LOCK_DIR", str(tmp_path))
288+
monkeypatch.setattr(utils, "require_root", require_root_mock)
282289
monkeypatch.setattr(main, "initialize_logger", initialize_logger_mock)
283290
monkeypatch.setattr(toolopts, "CLI", toolopts_cli_mock)
284291
monkeypatch.setattr(main, "show_eula", show_eula_mock)
285292
monkeypatch.setattr(breadcrumbs, "finish_collection", finish_collection_mock)
286293

287294
assert main.main() == 1
295+
assert require_root_mock.call_count == 1
288296
assert initialize_logger_mock.call_count == 1
289297
assert toolopts_cli_mock.call_count == 1
290298
assert show_eula_mock.call_count == 1
291299
assert finish_collection_mock.call_count == 1
292-
assert "No changes were made to the system." in caplog.records[-1].message
300+
assert "No changes were made to the system." in caplog.records[-2].message
293301

294302

295-
def test_main_traceback_before_action_completion(monkeypatch, caplog):
303+
def test_main_traceback_before_action_completion(monkeypatch, caplog, tmp_path):
304+
require_root_mock = mock.Mock()
296305
initialize_logger_mock = mock.Mock()
297306
toolopts_cli_mock = mock.Mock()
298307
show_eula_mock = mock.Mock()
@@ -309,6 +318,8 @@ def test_main_traceback_before_action_completion(monkeypatch, caplog):
309318
rollback_changes_mock = mock.Mock()
310319
summary_as_json_mock = mock.Mock()
311320

321+
monkeypatch.setattr(applock, "_DEFAULT_LOCK_DIR", str(tmp_path))
322+
monkeypatch.setattr(utils, "require_root", require_root_mock)
312323
monkeypatch.setattr(main, "initialize_logger", initialize_logger_mock)
313324
monkeypatch.setattr(toolopts, "CLI", toolopts_cli_mock)
314325
monkeypatch.setattr(main, "show_eula", show_eula_mock)
@@ -324,6 +335,7 @@ def test_main_traceback_before_action_completion(monkeypatch, caplog):
324335
monkeypatch.setattr(report, "summary_as_json", summary_as_json_mock)
325336

326337
assert main.main() == 1
338+
assert require_root_mock.call_count == 1
327339
assert initialize_logger_mock.call_count == 1
328340
assert toolopts_cli_mock.call_count == 1
329341
assert show_eula_mock.call_count == 1
@@ -338,13 +350,14 @@ def test_main_traceback_before_action_completion(monkeypatch, caplog):
338350
assert summary_as_json_mock.call_count == 0
339351
print(caplog.records)
340352
assert (
341-
caplog.records[-1].message.strip()
353+
caplog.records[-2].message.strip()
342354
== "Conversion interrupted before analysis of system completed. Report not generated."
343355
)
344-
assert "Action Framework Crashed" in caplog.records[-2].message
356+
assert "Action Framework Crashed" in caplog.records[-3].message
345357

346358

347-
def test_main_rollback_pre_ponr_changes_phase(monkeypatch, caplog):
359+
def test_main_rollback_pre_ponr_changes_phase(monkeypatch, caplog, tmp_path):
360+
require_root_mock = mock.Mock()
348361
initialize_logger_mock = mock.Mock()
349362
toolopts_cli_mock = mock.Mock()
350363
show_eula_mock = mock.Mock()
@@ -363,6 +376,8 @@ def test_main_rollback_pre_ponr_changes_phase(monkeypatch, caplog):
363376
rollback_changes_mock = mock.Mock()
364377
summary_as_json_mock = mock.Mock()
365378

379+
monkeypatch.setattr(applock, "_DEFAULT_LOCK_DIR", str(tmp_path))
380+
monkeypatch.setattr(utils, "require_root", require_root_mock)
366381
monkeypatch.setattr(main, "initialize_logger", initialize_logger_mock)
367382
monkeypatch.setattr(toolopts, "CLI", toolopts_cli_mock)
368383
monkeypatch.setattr(main, "show_eula", show_eula_mock)
@@ -380,6 +395,7 @@ def test_main_rollback_pre_ponr_changes_phase(monkeypatch, caplog):
380395
monkeypatch.setattr(report, "summary_as_json", summary_as_json_mock)
381396

382397
assert main.main() == 1
398+
assert require_root_mock.call_count == 1
383399
assert initialize_logger_mock.call_count == 1
384400
assert toolopts_cli_mock.call_count == 1
385401
assert show_eula_mock.call_count == 1
@@ -394,11 +410,12 @@ def test_main_rollback_pre_ponr_changes_phase(monkeypatch, caplog):
394410
assert finish_collection_mock.call_count == 1
395411
assert rollback_changes_mock.call_count == 1
396412
assert summary_as_json_mock.call_count == 1
397-
assert caplog.records[-2].message == "Conversion failed."
398-
assert caplog.records[-2].levelname == "CRITICAL"
413+
assert caplog.records[-3].message == "Conversion failed."
414+
assert caplog.records[-3].levelname == "CRITICAL"
399415

400416

401-
def test_main_rollback_analyze_exit_phase(global_tool_opts, monkeypatch):
417+
def test_main_rollback_analyze_exit_phase(global_tool_opts, monkeypatch, tmp_path):
418+
require_root_mock = mock.Mock()
402419
initialize_logger_mock = mock.Mock()
403420
toolopts_cli_mock = mock.Mock()
404421
show_eula_mock = mock.Mock()
@@ -416,6 +433,8 @@ def test_main_rollback_analyze_exit_phase(global_tool_opts, monkeypatch):
416433
finish_collection_mock = mock.Mock()
417434
rollback_changes_mock = mock.Mock()
418435

436+
monkeypatch.setattr(applock, "_DEFAULT_LOCK_DIR", str(tmp_path))
437+
monkeypatch.setattr(utils, "require_root", require_root_mock)
419438
monkeypatch.setattr(main, "initialize_logger", initialize_logger_mock)
420439
monkeypatch.setattr(toolopts, "CLI", toolopts_cli_mock)
421440
monkeypatch.setattr(main, "show_eula", show_eula_mock)
@@ -434,6 +453,7 @@ def test_main_rollback_analyze_exit_phase(global_tool_opts, monkeypatch):
434453
global_tool_opts.activity = "analysis"
435454

436455
assert main.main() == 0
456+
assert require_root_mock.call_count == 1
437457
assert initialize_logger_mock.call_count == 1
438458
assert toolopts_cli_mock.call_count == 1
439459
assert show_eula_mock.call_count == 1
@@ -449,7 +469,8 @@ def test_main_rollback_analyze_exit_phase(global_tool_opts, monkeypatch):
449469
assert summary_as_json_mock.call_count == 1
450470

451471

452-
def test_main_rollback_post_ponr_changes_phase(monkeypatch, caplog):
472+
def test_main_rollback_post_ponr_changes_phase(monkeypatch, caplog, tmp_path):
473+
require_root_mock = mock.Mock()
453474
initialize_logger_mock = mock.Mock()
454475
toolopts_cli_mock = mock.Mock()
455476
show_eula_mock = mock.Mock()
@@ -470,6 +491,8 @@ def test_main_rollback_post_ponr_changes_phase(monkeypatch, caplog):
470491
finish_collection_mock = mock.Mock()
471492
update_rhsm_custom_facts_mock = mock.Mock()
472493

494+
monkeypatch.setattr(applock, "_DEFAULT_LOCK_DIR", str(tmp_path))
495+
monkeypatch.setattr(utils, "require_root", require_root_mock)
473496
monkeypatch.setattr(main, "initialize_logger", initialize_logger_mock)
474497
monkeypatch.setattr(toolopts, "CLI", toolopts_cli_mock)
475498
monkeypatch.setattr(main, "show_eula", show_eula_mock)
@@ -489,6 +512,7 @@ def test_main_rollback_post_ponr_changes_phase(monkeypatch, caplog):
489512
monkeypatch.setattr(report, "summary_as_json", summary_as_json_mock)
490513

491514
assert main.main() == 1
515+
assert require_root_mock.call_count == 1
492516
assert initialize_logger_mock.call_count == 1
493517
assert toolopts_cli_mock.call_count == 1
494518
assert show_eula_mock.call_count == 1
@@ -504,5 +528,5 @@ def test_main_rollback_post_ponr_changes_phase(monkeypatch, caplog):
504528
assert post_ponr_conversion_mock.call_count == 1
505529
assert finish_collection_mock.call_count == 1
506530
assert summary_as_json_mock.call_count == 1
507-
assert "The system is left in an undetermined state that Convert2RHEL cannot fix." in caplog.records[-1].message
531+
assert "The system is left in an undetermined state that Convert2RHEL cannot fix." in caplog.records[-2].message
508532
assert update_rhsm_custom_facts_mock.call_count == 1

0 commit comments

Comments
 (0)