Skip to content

Commit 5041164

Browse files
authored
Merge pull request #294 from bocekm/add_option_to_not_remove_rhsm
Allow conversions of offline systems
2 parents 8a82388 + 6660580 commit 5041164

File tree

6 files changed

+135
-17
lines changed

6 files changed

+135
-17
lines changed

convert2rhel/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ def pre_ponr_conversion():
170170
subscription.download_rhsm_pkgs()
171171
loggerinst.task("Convert: Subscription Manager - Replace")
172172
subscription.replace_subscription_manager()
173+
loggerinst.task("Convert: Subscription Manager - Verify installation")
174+
subscription.verify_rhsm_installed()
173175
loggerinst.task("Convert: Install RHEL certificates for RHSM")
174176
system_cert = cert.SystemCert()
175177
system_cert.install()

convert2rhel/subscription.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ def subscribe_system():
7777
def unregister_system():
7878
"""Unregister the system from RHSM."""
7979
loggerinst.info("Unregistering the system.")
80+
if tool_opts.keep_rhsm:
81+
loggerinst.info("Skipping due to the use of --keep-rhsm.")
82+
return
83+
8084
submgr_installed = pkghandler.get_installed_pkg_objects("subscription-manager")
8185
if not submgr_installed:
8286
loggerinst.info("The subscription-manager package is not installed.")
@@ -188,6 +192,10 @@ def replace_subscription_manager():
188192
Make sure the system is unregistered before removing the subscription-manager as not doing so would leave the
189193
system to be still registered on the server side, making it dificult for an admin to unregister it afterwards.
190194
"""
195+
if tool_opts.keep_rhsm:
196+
loggerinst.info("Skipping due to the use of --keep-rhsm.")
197+
return
198+
191199
if not os.path.isdir(SUBMGR_RPMS_DIR) or not os.listdir(SUBMGR_RPMS_DIR):
192200
loggerinst.critical("The %s directory does not exist or is empty." % SUBMGR_RPMS_DIR)
193201

@@ -347,11 +355,26 @@ def get_repo(repos_raw):
347355
yield repo_id
348356

349357

358+
def verify_rhsm_installed():
359+
"""Make sure that subscription-manager has been installed."""
360+
if not pkghandler.get_installed_pkg_objects("subscription-manager"):
361+
if tool_opts.keep_rhsm:
362+
loggerinst.critical(
363+
"When using the --keep-rhsm option, the subscription-manager needs to be installed before"
364+
" executing convert2rhel."
365+
)
366+
else:
367+
# Most probably this condition will not be hit. If the installation of subscription-manager fails, the
368+
# conversion stops already at that point.
369+
loggerinst.critical("The subscription-manager package is not installed correctly.")
370+
else:
371+
loggerinst.info("subscription-manager installed correctly.")
372+
373+
350374
def disable_repos():
351375
"""Before enabling specific repositories, all repositories should be
352376
disabled. This can be overriden by the --disablerepo option.
353377
"""
354-
355378
disable_cmd = ""
356379
for repo in tool_opts.disablerepo:
357380
disable_cmd += " --disable=%s" % repo
@@ -423,6 +446,9 @@ def download_rhsm_pkgs():
423446
The packages are available in non-standard repositories, so additional repofiles need to be used. The downloaded
424447
RPMs are to be installed in a later stage of the conversion.
425448
"""
449+
if tool_opts.keep_rhsm:
450+
loggerinst.info("Skipping due to the use of --keep-rhsm.")
451+
return
426452
utils.mkdir_p(_RHSM_TMP_DIR)
427453
pkgs_to_download = ["subscription-manager", "subscription-manager-rhsm-certificates"]
428454

convert2rhel/toolopts.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def __init__(self):
4444
self.arch = None
4545
self.no_rpm_va = False
4646
self.disable_colors = False
47+
self.keep_rhsm = False
4748

4849
# set True when credentials (username & password) are given through CLI
4950
self.credentials_thru_cli = False
@@ -61,16 +62,13 @@ def _get_argparser():
6162
"\n"
6263
" convert2rhel [-h]\n"
6364
" convert2rhel [--version]\n"
64-
" convert2rhel [-u username] [-p password | -f pswd_file]"
65-
" [--pool pool_id | -a] [--disablerepo repoid] [--enablerepo"
66-
" repoid] [--serverurl url] [--no-rpm-va]"
67-
" [--debug] [--restart] [-y]\n"
65+
" convert2rhel [-u username] [-p password | -f pswd_file] [--pool pool_id | -a] [--disablerepo repoid]"
66+
" [--enablerepo repoid] [--serverurl url] [--keep-rhsm] [--no-rpm-va] [--debug] [--restart]"
67+
" [--disable-colors] [-y]\n"
6868
" convert2rhel [--no-rhsm] [--disablerepo repoid]"
69-
" [--enablerepo repoid] [--no-rpm-va] [--debug] [--restart] [-y]\n"
70-
" convert2rhel [-k key] [-o organization] [--pool pool_id |"
71-
" -a] [--disablerepo repoid] [--enablerepo repoid]"
72-
" [--serverurl url] [--no-rpm-va] [--debug]"
73-
" [--restart] [--disable-colors] [-y]"
69+
" [--enablerepo repoid] [--no-rpm-va] [--debug] [--restart] [--disable-colors] [-y]\n"
70+
" convert2rhel [-k key] [-o organization] [--pool pool_id | -a] [--disablerepo repoid] [--enablerepo"
71+
" repoid] [--serverurl url] [--keep-rhsm] [--no-rpm-va] [--debug] [--restart] [--disable-colors] [-y]"
7472
"\n\n"
7573
"WARNING: The tool needs to be run under the root user"
7674
)
@@ -210,6 +208,15 @@ def _register_options(self):
210208
" The default is the Customer Portal Subscription Management service. It is not to be used to specify a"
211209
" Satellite server. For that, read the product documentation at https://access.redhat.com/.",
212210
)
211+
group.add_option(
212+
"--keep-rhsm",
213+
action="store_true",
214+
help="Keep the already installed Red Hat Subscription Management-related packages. By default,"
215+
" during the conversion, these packages are removed, downloaded from verified sources and re-installed."
216+
" This option is suitable for environments with no connection to the Internet, or for systems managed by"
217+
" Red Hat Satellite. Warning: The system is being re-registered during the conversion and when the"
218+
" re-registration fails, there's no automated rollback to the original registration.",
219+
)
213220
self._parser.add_option_group(group)
214221

215222
group = optparse.OptionGroup(
@@ -282,7 +289,7 @@ def _process_cli_options(self):
282289
if parsed_opts.no_rhsm or parsed_opts.disable_submgr:
283290
tool_opts.no_rhsm = True
284291
if not tool_opts.enablerepo:
285-
loggerinst.critical("The --enablerepo option is required if --disable-submgr or --no-rhsm is passed.")
292+
loggerinst.critical("The --enablerepo option is required when --disable-submgr or --no-rhsm is used.")
286293
if not tool_opts.disablerepo:
287294
# Default to disable every repo except:
288295
# - the ones passed through --enablerepo
@@ -293,13 +300,21 @@ def _process_cli_options(self):
293300
tool_opts.pool = parsed_opts.pool
294301

295302
if parsed_opts.serverurl:
296-
if parsed_opts.no_rhsm:
303+
if tool_opts.no_rhsm:
297304
loggerinst.warning(
298305
"Ignoring the --serverurl option. It has no effect when --disable-submgr or --no-rhsm is used."
299306
)
300307
else:
301308
tool_opts.serverurl = parsed_opts.serverurl
302309

310+
if parsed_opts.keep_rhsm:
311+
if tool_opts.no_rhsm:
312+
loggerinst.warning(
313+
"Ignoring the --keep-rhsm option. It has no effect when --disable-submgr or --no-rhsm is used."
314+
)
315+
else:
316+
tool_opts.keep_rhsm = parsed_opts.keep_rhsm
317+
303318
tool_opts.autoaccept = parsed_opts.y
304319
tool_opts.auto_attach = parsed_opts.auto_attach
305320
tool_opts.restart = parsed_opts.restart

convert2rhel/unit_tests/main_test.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ def test_rollback_changes(self):
154154
@mock_calls(main.checks, "perform_pre_ponr_checks", CallOrderMocked)
155155
@mock_calls(pkghandler, "remove_excluded_pkgs", CallOrderMocked)
156156
@mock_calls(subscription, "replace_subscription_manager", CallOrderMocked)
157+
@mock_calls(subscription, "verify_rhsm_installed", CallOrderMocked)
157158
@mock_calls(pkghandler, "remove_repofile_pkgs", CallOrderMocked)
158159
@mock_calls(cert.SystemCert, "install", CallOrderMocked)
159160
@mock_calls(redhatrelease.YumConf, "patch", CallOrderMocked)
@@ -175,6 +176,7 @@ def test_pre_ponr_conversion_order_with_rhsm(self):
175176
intended_call_order["check_and_resolve"] = 1
176177
intended_call_order["download_rhsm_pkgs"] = 1
177178
intended_call_order["replace_subscription_manager"] = 1
179+
intended_call_order["verify_rhsm_installed"] = 1
178180
intended_call_order["install"] = 1
179181
intended_call_order["subscribe_system"] = 1
180182
intended_call_order["get_rhel_repoids"] = 1
@@ -200,6 +202,7 @@ def test_pre_ponr_conversion_order_with_rhsm(self):
200202
@mock_calls(main.checks, "perform_pre_ponr_checks", CallOrderMocked)
201203
@mock_calls(pkghandler, "remove_excluded_pkgs", CallOrderMocked)
202204
@mock_calls(subscription, "replace_subscription_manager", CallOrderMocked)
205+
@mock_calls(subscription, "verify_rhsm_installed", CallOrderMocked)
203206
@mock_calls(pkghandler, "remove_repofile_pkgs", CallOrderMocked)
204207
@mock_calls(cert.SystemCert, "install", CallOrderMocked)
205208
@mock_calls(redhatrelease.YumConf, "patch", CallOrderMocked)
@@ -224,6 +227,7 @@ def test_pre_ponr_conversion_order_without_rhsm(self):
224227
# Do not expect this one to be called - related to RHSM
225228
intended_call_order["download_rhsm_pkgs"] = 0
226229
intended_call_order["replace_subscription_manager"] = 0
230+
intended_call_order["verify_rhsm_installed"] = 0
227231
intended_call_order["install"] = 0
228232
intended_call_order["subscribe_system"] = 0
229233
intended_call_order["get_rhel_repoids"] = 0

convert2rhel/unit_tests/subscription_test.py

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ def __call__(self, pkg, dest, reposdir=None):
409409
(False, False),
410410
),
411411
)
412-
def test_unregister_system_successfully(submgr_installed, unregistration_failure, monkeypatch, caplog):
412+
def test_unregister_system(submgr_installed, unregistration_failure, monkeypatch, caplog):
413413
if unregistration_failure:
414414
monkeypatch.setattr(utils, "run_subprocess", mock.Mock(return_value=("output", 1)))
415415
else:
@@ -426,11 +426,63 @@ def test_unregister_system_successfully(submgr_installed, unregistration_failure
426426

427427
if submgr_installed:
428428
utils.run_subprocess.assert_called_once()
429-
430-
if submgr_installed:
431429
if unregistration_failure:
432430
assert "System unregistration failed" in caplog.text
433431
else:
434432
assert "System unregistered successfully." in caplog.text
435433
else:
436434
assert "The subscription-manager package is not installed." in caplog.text
435+
436+
437+
@mock.patch("convert2rhel.toolopts.tool_opts.keep_rhsm", True)
438+
def test_unregister_system_skipped(monkeypatch, caplog):
439+
monkeypatch.setattr(pkghandler, "get_installed_pkg_objects", mock.Mock())
440+
subscription.unregister_system()
441+
assert "Skipping due to the use of --keep-rhsm." in caplog.text
442+
pkghandler.get_installed_pkg_objects.assert_not_called()
443+
444+
445+
@mock.patch("convert2rhel.toolopts.tool_opts.keep_rhsm", True)
446+
def test_replace_subscription_manager_skipped(monkeypatch, caplog):
447+
monkeypatch.setattr(subscription, "unregister_system", mock.Mock())
448+
subscription.replace_subscription_manager()
449+
assert "Skipping due to the use of --keep-rhsm." in caplog.text
450+
subscription.unregister_system.assert_not_called()
451+
452+
453+
@mock.patch("convert2rhel.toolopts.tool_opts.keep_rhsm", True)
454+
def test_download_rhsm_pkgs_skipped(monkeypatch, caplog):
455+
monkeypatch.setattr(subscription, "_download_rhsm_pkgs", mock.Mock())
456+
subscription.download_rhsm_pkgs()
457+
assert "Skipping due to the use of --keep-rhsm." in caplog.text
458+
subscription._download_rhsm_pkgs.assert_not_called()
459+
460+
461+
@pytest.mark.parametrize(
462+
("submgr_installed", "keep_rhsm", "critical_string"),
463+
(
464+
(True, None, None),
465+
(False, True, "the subscription-manager needs to be installed"),
466+
(False, False, "The subscription-manager package is not installed correctly."),
467+
),
468+
)
469+
def test_verify_rhsm_installed(submgr_installed, keep_rhsm, critical_string, monkeypatch, caplog):
470+
if keep_rhsm:
471+
monkeypatch.setattr(tool_opts, "keep_rhsm", keep_rhsm)
472+
473+
if submgr_installed:
474+
monkeypatch.setattr(
475+
pkghandler, "get_installed_pkg_objects", lambda _: [namedtuple("Pkg", ["name"])("subscription-manager")]
476+
)
477+
478+
subscription.verify_rhsm_installed()
479+
480+
assert "subscription-manager installed correctly." in caplog.text
481+
482+
else:
483+
monkeypatch.setattr(pkghandler, "get_installed_pkg_objects", lambda _: None)
484+
485+
with pytest.raises(SystemExit):
486+
subscription.verify_rhsm_installed()
487+
488+
assert critical_string in caplog.text

convert2rhel/unit_tests/toolopts_test.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,24 @@ def test_cmdline_disablerepo_defaults_to_asterisk(self):
8080
self.assertEqual(tool_opts.disablerepo, ["*"])
8181

8282

83+
@pytest.mark.parametrize(
84+
("argv", "warn", "keep_rhsm_value"),
85+
(
86+
(mock_cli_arguments(["--keep-rhsm"]), False, True),
87+
(mock_cli_arguments(["--keep-rhsm", "--disable-submgr", "--enablerepo", "test_repo"]), True, False),
88+
),
89+
)
90+
@mock.patch("convert2rhel.toolopts.tool_opts.keep_rhsm", False)
91+
def test_keep_rhsm(argv, warn, keep_rhsm_value, monkeypatch, caplog):
92+
monkeypatch.setattr(sys, "argv", argv)
93+
convert2rhel.toolopts.CLI()
94+
if warn:
95+
assert "Ignoring the --keep-rhsm option" in caplog.text
96+
else:
97+
assert "Ignoring the --keep-rhsm option" not in caplog.text
98+
assert convert2rhel.toolopts.tool_opts.keep_rhsm == keep_rhsm_value
99+
100+
83101
@pytest.mark.parametrize(
84102
("argv", "warn", "ask_to_continue"),
85103
(
@@ -109,19 +127,20 @@ def test_cmdline_obsolete_variant_option(argv, warn, ask_to_continue, monkeypatc
109127
("argv", "raise_exception", "no_rhsm_value"),
110128
(
111129
(mock_cli_arguments(["--disable-submgr"]), True, True),
130+
(mock_cli_arguments(["--no-rhsm"]), True, True),
112131
(mock_cli_arguments(["--disable-submgr", "--enablerepo", "test_repo"]), False, True),
113132
(mock_cli_arguments(["--no-rhsm", "--disable-submgr", "--enablerepo", "test_repo"]), False, True),
114-
(mock_cli_arguments(["--no-rhsm"]), False, True),
115133
),
116134
)
117135
@mock.patch("convert2rhel.toolopts.tool_opts.no_rhsm", False)
136+
@mock.patch("convert2rhel.toolopts.tool_opts.enablerepo", [])
118137
def test_both_disable_submgr_and_no_rhsm_options_work(argv, raise_exception, no_rhsm_value, monkeypatch, caplog):
119138
monkeypatch.setattr(sys, "argv", argv)
120139

121140
if raise_exception:
122141
with pytest.raises(SystemExit):
123142
convert2rhel.toolopts.CLI()
124-
assert "The --enablerepo option is required if --disable-submgr or --no-rhsm is passed." in caplog.text
143+
assert "The --enablerepo option is required when --disable-submgr or --no-rhsm is used." in caplog.text
125144
else:
126145
convert2rhel.toolopts.CLI()
127146

0 commit comments

Comments
 (0)