Skip to content

Commit 59b7894

Browse files
prilrclaude
authored andcommitted
CLOS-3960: Fix EnableYumSpacewalkPlugin actor for CL7 -> CL8 upgrade
The FirstBoot-phase actor that re-enables the spacewalk plugin after a CL7 -> CL8 upgrade had several defects that combined to leave the plugin disabled on CL8 and break CLN dynamic channel resolution. The main one is the hardcoded YUM path /etc/yum/pluginconf.d/spacewalk.conf, which does not exist on the target system. After the PES replacement yum-rhn-plugin -> dnf-plugin-spacewalk (pes-events id=1586) the CL8 plugin config lives at /etc/dnf/plugins/spacewalk.conf. Fix: point self.config at the DNF path and split the logic into a pure helper _enable_plugin() in libraries/enableyumspacewalkplugin.py. Under the no-auth / SWNG transition (CLOS-4056) rhn-client-tools >= 3.0.1 Obsoletes dnf-plugin-spacewalk, so the config file is gone by design on no-auth systems; emitting a "config not found" report there would just be noise. Plugin-config presence is the discriminator: we enable it whether it's found. On a system that transitions to no-auth it won't matter, because the plugin is gone. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
1 parent ca123a0 commit 59b7894

3 files changed

Lines changed: 110 additions & 37 deletions

File tree

repos/system_upgrade/cloudlinux/actors/enableyumspacewalkplugin/actor.py

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,25 @@
33
from leapp import reporting
44
from leapp.reporting import Report
55
from leapp.libraries.common.cllaunch import run_on_cloudlinux
6-
7-
8-
try:
9-
# py2
10-
import ConfigParser as configparser
11-
ParserClass = configparser.SafeConfigParser
12-
except Exception:
13-
# py3
14-
import configparser
15-
ParserClass = configparser.ConfigParser
6+
from leapp.libraries.actor import enableyumspacewalkplugin
167

178

189
class EnableYumSpacewalkPlugin(Actor):
19-
"""
20-
Enable yum spacewalk plugin if it's disabled
21-
Required for the CLN channel functionality to work properly
22-
"""
23-
24-
name = 'enable_yum_spacewalk_plugin'
10+
name = "enable_yum_spacewalk_plugin"
2511
consumes = ()
2612
produces = (Report,)
2713
tags = (FirstBootPhaseTag, IPUWorkflowTag)
28-
29-
config = '/etc/yum/pluginconf.d/spacewalk.conf'
14+
config = enableyumspacewalkplugin.DEFAULT_CONFIG_PATH
3015

3116
@run_on_cloudlinux
3217
def process(self):
33-
summary = 'yum spacewalk plugin must be enabled for the CLN channels to work properly. ' \
34-
'Please make sure it is enabled. Default config path is "%s"' % self.config
35-
title = None
36-
37-
parser = ParserClass(allow_no_value=True)
38-
try:
39-
red = parser.read(self.config)
40-
if not red:
41-
title = 'yum spacewalk plugin config not found'
42-
if parser.get('main', 'enabled') != '1':
43-
parser.set('main', 'enabled', '1')
44-
with open(self.config, 'w') as f:
45-
parser.write(f)
46-
self.log.info('yum spacewalk plugin enabled')
47-
return
48-
except Exception as e:
49-
title = 'yum spacewalk plugin config error: %s' % e
50-
18+
_, title = enableyumspacewalkplugin._enable_plugin(
19+
self.config, enableyumspacewalkplugin.ParserClass, self.log
20+
)
5121
if title:
5222
reporting.create_report([
5323
reporting.Title(title),
54-
reporting.Summary(summary),
24+
reporting.Summary("DNF spacewalk plugin must be enabled for CLN channels. Config path: " + self.config),
5525
reporting.Severity(reporting.Severity.MEDIUM),
5626
reporting.Groups([reporting.Groups.SANITY])
5727
])
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import os
2+
3+
try:
4+
# py2
5+
import ConfigParser as configparser
6+
ParserClass = configparser.SafeConfigParser
7+
except ImportError:
8+
# py3
9+
import configparser
10+
ParserClass = configparser.ConfigParser
11+
12+
13+
# DNF plugin config path on the target system (CL8). FirstBoot runs after the
14+
# target OS is already in place; on CL8 the plugin package is
15+
# dnf-plugin-spacewalk (PES replacement for CL7's yum-rhn-plugin,
16+
# pes-events id=1586) and its config ships with enabled=0.
17+
DEFAULT_CONFIG_PATH = '/etc/dnf/plugins/spacewalk.conf'
18+
19+
20+
def _enable_plugin(config_path, parser_cls=ParserClass, log=None):
21+
"""Enable the DNF spacewalk plugin at `config_path`.
22+
23+
Returns `(changed, title)` where `title` is `None` on success or
24+
when the plugin is not installed, and otherwise a human-readable
25+
problem description suitable for a Leapp report.
26+
27+
Absence of `config_path` is treated as a silent skip: on no-auth /
28+
SWNG systems (CLOS-4056) `rhn-client-tools >= 3.0.1` Obsoletes the
29+
`dnf-plugin-spacewalk` package, so the config file is either gone by
30+
then, or doesn't do anything.
31+
"""
32+
if not os.path.exists(config_path):
33+
return False, None
34+
parser = parser_cls(allow_no_value=True)
35+
try:
36+
parser.read(config_path)
37+
if parser.get('main', 'enabled') != '1':
38+
parser.set('main', 'enabled', '1')
39+
with open(config_path, 'w') as f:
40+
parser.write(f)
41+
if log is not None:
42+
log.info('DNF spacewalk plugin enabled')
43+
return True, None
44+
return False, None
45+
except Exception as e:
46+
return False, 'DNF spacewalk plugin config error: %s' % e
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
try:
2+
import ConfigParser as configparser # py2
3+
ParserClass = configparser.SafeConfigParser
4+
except ImportError:
5+
import configparser # py3
6+
ParserClass = configparser.ConfigParser
7+
8+
from leapp.libraries.actor.enableyumspacewalkplugin import _enable_plugin
9+
10+
11+
def _write(tmp_path, body):
12+
p = tmp_path / "spacewalk.conf"
13+
p.write_text(body)
14+
return str(p)
15+
16+
17+
def test_missing_config_is_silent_skip(tmp_path):
18+
"""Config file absent -> silent skip: no change, no title, no report.
19+
20+
On no-auth / SWNG systems (CLOS-4056) the dnf-plugin-spacewalk
21+
package is Obsoleted by rhn-client-tools >= 3.0.1 and the config
22+
file is absent by design. Emitting a 'not found' report there
23+
would be noise.
24+
"""
25+
changed, title = _enable_plugin(str(tmp_path / "absent.conf"), ParserClass)
26+
assert changed is False
27+
assert title is None
28+
29+
30+
def test_flips_enabled_zero_to_one(tmp_path):
31+
"""Config present with enabled=0 -> flipped to 1, changed=True, no title."""
32+
cfg = _write(tmp_path, "[main]\nenabled = 0\n")
33+
changed, title = _enable_plugin(cfg, ParserClass)
34+
assert changed is True
35+
assert title is None
36+
updated = open(cfg).read()
37+
# ConfigParser may write either 'enabled = 1' or 'enabled=1'; accept both.
38+
assert "enabled = 1" in updated or "enabled=1" in updated
39+
40+
41+
def test_already_enabled_is_noop(tmp_path):
42+
"""Config present with enabled=1 -> no change, no title, file untouched."""
43+
cfg = _write(tmp_path, "[main]\nenabled = 1\n")
44+
original = open(cfg).read()
45+
changed, title = _enable_plugin(cfg, ParserClass)
46+
assert changed is False
47+
assert title is None
48+
assert open(cfg).read() == original
49+
50+
51+
def test_missing_main_section_returns_config_error(tmp_path):
52+
"""Config present but missing [main] -> title reports config error."""
53+
cfg = _write(tmp_path, "[other]\nenabled = 0\n")
54+
changed, title = _enable_plugin(cfg, ParserClass)
55+
assert changed is False
56+
assert title is not None
57+
assert "config error" in title.lower()

0 commit comments

Comments
 (0)