Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from leapp.actors import Actor
from leapp import reporting
from leapp.libraries.stdlib import api
from leapp.reporting import Report
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
from leapp.libraries.common.cllaunch import run_on_cloudlinux
from leapp.libraries.common.cln_detect import is_cln_package_channel_active


class CheckRhnVersionOverride(Actor):
Expand All @@ -17,23 +19,37 @@ class CheckRhnVersionOverride(Actor):

@run_on_cloudlinux
def process(self):
if not is_cln_package_channel_active():
# CLOS-4056: versionOverride only matters when CLN is delivering packages,
# since the upgrade rewrites it to drive channel selection.
# On no-auth systems this does not apply.
return

up2date_config = '/etc/sysconfig/rhn/up2date'
with open(up2date_config, 'r') as f:
config_data = f.readlines()
for line in config_data:
if line.startswith('versionOverride='):
stripped_line = line.strip().split("=")
versionOverrideValue = stripped_line[1]
# If the version is being overriden to 8, we can continue as is.
if versionOverrideValue not in ['', '8']:
title = 'RHN up2date: versionOverride overwritten by the upgrade'
summary = ("The RHN config file up2date has a set value of the versionOverride option: {}."
" This value will get overwritten by the upgrade process, and reset to an empty"
" value once it's complete.".format(versionOverrideValue))
reporting.create_report([
reporting.Title(title),
reporting.Summary(summary),
reporting.Severity(reporting.Severity.MEDIUM),
reporting.Groups([reporting.Groups.OS_FACTS]),
reporting.RelatedResource('file', '/etc/sysconfig/rhn/up2date')
])
try:
with open(up2date_config, 'r') as f:
config_data = f.readlines()
except (OSError, IOError):
api.current_logger().info(
"RHN up2date config %s not present; skipping versionOverride check",
up2date_config,
)
return

for line in config_data:
if line.startswith('versionOverride='):
stripped_line = line.strip().split("=")
versionOverrideValue = stripped_line[1]
# If the version is being overriden to 8, we can continue as is.
if versionOverrideValue not in ['', '8']:
title = 'RHN up2date: versionOverride overwritten by the upgrade'
summary = ("The RHN config file up2date has a set value of the versionOverride option: {}."
" This value will get overwritten by the upgrade process, and reset to an empty"
" value once it's complete.".format(versionOverrideValue))
reporting.create_report([
reporting.Title(title),
reporting.Summary(summary),
reporting.Severity(reporting.Severity.MEDIUM),
reporting.Groups([reporting.Groups.OS_FACTS]),
reporting.RelatedResource('file', '/etc/sysconfig/rhn/up2date')
])
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
ParserClass = configparser.ConfigParser


# DNF plugin config path on the target system (CL8). FirstBoot runs after the
# target OS is already in place; on CL8 the plugin package is
# dnf-plugin-spacewalk (PES replacement for CL7's yum-rhn-plugin,
# pes-events id=1586) and its config ships with enabled=0.
# DNF plugin config path on the target system (CL8).
# FirstBoot runs after the target OS is already in place;
# on CL8 the plugin package is dnf-plugin-spacewalk
# (PES replacement for CL7's yum-rhn-plugin, pes-events id=1586)
# and its config ships with enabled=0.
DEFAULT_CONFIG_PATH = '/etc/dnf/plugins/spacewalk.conf'


Expand All @@ -24,8 +25,8 @@ def _enable_plugin(config_path, parser_cls=ParserClass, log=None):
when the plugin is not installed, and otherwise a human-readable
problem description suitable for a Leapp report.

Absence of `config_path` is treated as a silent skip: on no-auth /
SWNG systems (CLOS-4056) `rhn-client-tools >= 3.0.1` Obsoletes the
Absence of `config_path` is treated as a silent skip: on no-auth
systems (CLOS-4056) `rhn-client-tools >= 3.0.1` Obsoletes the
`dnf-plugin-spacewalk` package, so the config file is either gone by
then, or doesn't do anything.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ def _write(tmp_path, body):
def test_missing_config_is_silent_skip(tmp_path):
"""Config file absent -> silent skip: no change, no title, no report.

On no-auth / SWNG systems (CLOS-4056) the dnf-plugin-spacewalk
package is Obsoleted by rhn-client-tools >= 3.0.1 and the config
file is absent by design. Emitting a 'not found' report there
would be noise.
On no-auth systems (CLOS-4056) the dnf-plugin-spacewalk
package is Obsoleted by rhn-client-tools >= 3.0.1.
Emitting a 'not found' report there would be noise.
"""
changed, title = _enable_plugin(str(tmp_path / "absent.conf"), ParserClass)
assert changed is False
Expand Down
20 changes: 17 additions & 3 deletions repos/system_upgrade/cloudlinux/actors/pinclnmirror/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from leapp.actors import Actor
from leapp.libraries.stdlib import api
from leapp.libraries.common.cllaunch import run_on_cloudlinux
from leapp.libraries.common.cln_detect import is_cln_package_channel_active
from leapp.libraries.common.cln_switch import get_target_userspace_path
from leapp.tags import DownloadPhaseTag, IPUWorkflowTag
from leapp.libraries.common.config.version import get_target_major_version
Expand All @@ -25,6 +26,14 @@ class PinClnMirror(Actor):
@run_on_cloudlinux
def process(self):
"""Pin CLN mirror"""
if not is_cln_package_channel_active():
# CLOS-4056: pinning the CLN mirror is only meaningful when CLN is delivering packages.
# With the no-auth repo scheme active, there's no point in doing so.
api.current_logger().info(
"CLN is not the active package channel; skipping mirror pinning"
)
return

target_userspace = get_target_userspace_path()
api.current_logger().info("Pin CLN mirror: target userspace=%s", target_userspace)

Expand Down Expand Up @@ -54,6 +63,11 @@ def process(self):
api.current_logger().info("Pin CLN mirror %s in %s", mirror_url, mirrorlist_path)

up2date_path = os.path.join(target_userspace, 'etc/sysconfig/rhn/up2date')
with open(up2date_path, 'a+') as file:
file.write('\nmirrorURL[comment]=Set mirror URL to /etc/mirrorlist\nmirrorURL=file:///etc/mirrorlist\n')
api.current_logger().info("Updated up2date_path %s", up2date_path)
try:
with open(up2date_path, 'a+') as file:
file.write('\nmirrorURL[comment]=Set mirror URL to /etc/mirrorlist\nmirrorURL=file:///etc/mirrorlist\n')
api.current_logger().info("Updated up2date_path %s", up2date_path)
except (OSError, IOError) as e:
api.current_logger().info(
"Could not update %s: %s", up2date_path, e,
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from leapp.actors import Actor
from leapp.libraries.stdlib import api
from leapp.tags import FinalizationPhaseTag, IPUWorkflowTag
from leapp.libraries.common.cllaunch import run_on_cloudlinux
from leapp.libraries.common.cln_detect import is_cln_package_channel_active


class ResetRhnVersionOverride(Actor):
Expand All @@ -15,11 +17,28 @@ class ResetRhnVersionOverride(Actor):

@run_on_cloudlinux
def process(self):
if not is_cln_package_channel_active():
# CLOS-4056: versionOverride only matters when CLN is delivering packages,
# since the upgrade rewrites it to drive channel selection.
# On no-auth systems this does not apply.
return

up2date_config = '/etc/sysconfig/rhn/up2date'
with open(up2date_config, 'r') as f:
config_data = f.readlines()
for line in config_data:
if line.startswith('versionOverride='):
line = 'versionOverride='
try:
with open(up2date_config, 'r') as f:
config_data = f.readlines()
except (OSError, IOError):
api.current_logger().info(
"RHN up2date config %s not present; skipping versionOverride reset",
up2date_config,
)
return

new_data = []
for line in config_data:
if line.startswith('versionOverride='):
new_data.append('versionOverride=\n')
else:
new_data.append(line)
with open(up2date_config, 'w') as f:
f.writelines(config_data)
f.writelines(new_data)
28 changes: 22 additions & 6 deletions repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from leapp.tags import FirstBootPhaseTag, IPUWorkflowTag
from leapp.libraries.stdlib import CalledProcessError
from leapp.libraries.common.cllaunch import run_on_cloudlinux
from leapp.libraries.common.cln_switch import cln_switch, get_target_userspace_path
from leapp.libraries.common.cln_detect import is_cln_package_channel_active
from leapp.libraries.common.cln_switch import cln_switch
from leapp import reporting
from leapp.reporting import Report
from leapp.libraries.common.config.version import get_target_major_version
Expand All @@ -22,9 +23,21 @@ class SwitchClnChannel(Actor):

@run_on_cloudlinux
def process(self):
if not is_cln_package_channel_active():
# CLOS-4056: CLN package channel is inactive, so skipping the channel switch
# is correct - packages come from standard repositories instead.
# Leapp manages those without custom actions through repomaps.
api.current_logger().info(
"CLN is not the active package channel; skipping channel switch"
)
return

try:
cln_switch(target=int(get_target_major_version()))
except CalledProcessError as e:
# Do not inhibit. Even on systems that ARE using CLN as the package channel,
# a transient CLN-server reachability problem at FirstBoot
# shouldn't block the upgrade.
reporting.create_report(
[
reporting.Title(
Expand All @@ -33,17 +46,20 @@ def process(self):
reporting.Summary(
"Command {} failed with exit code {}."
" The most probable cause of that is a problem with this system's"
" CloudLinux Network registration.".format(e.command, e.exit_code)
" CloudLinux Network registration. If this system now uses the"
" no-auth (SWNG) repository scheme, this failure is harmless -"
" CL9 packages come from cl-channel / cloudlinux9-baseos instead"
" of CLN.".format(e.command, e.exit_code)
),
reporting.Remediation(
hint="Check the state of this system's registration with \'rhn_check\'."
" Attempt to re-register the system with \'rhnreg_ks --force\'."
hint="If you rely on CLN: check registration with 'rhn_check' and"
" re-register with 'rhnreg_ks --force'. If you have migrated to"
" no-auth repos, this message can be ignored."
),
reporting.Severity(reporting.Severity.HIGH),
reporting.Severity(reporting.Severity.MEDIUM),
reporting.Groups(
[reporting.Groups.OS_FACTS, reporting.Groups.AUTHENTICATION]
),
reporting.Groups([reporting.Groups.INHIBITOR]),
]
)
except OSError as e:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from leapp.actors import Actor
from leapp.libraries.common.cllaunch import run_on_cloudlinux
from leapp.libraries.common.cln_detect import is_cln_package_channel_active
from leapp.libraries.common.cln_switch import get_target_userspace_path
from leapp.tags import FirstBootPhaseTag, IPUWorkflowTag

Expand All @@ -19,6 +20,11 @@ class UnpinClnMirror(Actor):

@run_on_cloudlinux
def process(self):
if not is_cln_package_channel_active():
# CLOS-4056: pinclnmirror skipped its work for the same reason
# (CLN package channel inactive), so there is nothing for us to unpin.
return

target_userspace = get_target_userspace_path()

mirrorlist_path = os.path.join(target_userspace, 'etc/mirrorlist')
Expand Down
75 changes: 75 additions & 0 deletions repos/system_upgrade/cloudlinux/libraries/cln_detect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Detection helpers for the CloudLinux Network (CLN) package channel.

CLN has historically combined two concerns:

1. *Registration / identity* - the system is registered with the CLN
server (`/etc/sysconfig/rhn/systemid`, JWT token), used for licensing
regardless of how packages are delivered.

2. *Package delivery* - the system pulls CloudLinux packages
through the spacewalk DNF/YUM plugin against the
CLN-side channel (`cloudlinux-x86_64-server-N`).

The no-auth repository transition decouples these.
New CL8 and CL9 systems keep CLN *registration*,
but no longer use CLN as the *package channel* - packages come from the SWNG mirrorlist
via `/etc/yum.repos.d/cl.repo` (`cl-channel`) instead.
`rhn-client-tools >= 3.0.1` disables the spacewalk plugin to enforce this.

The CLN-touching actors in this repo only care about the second concern:
they exist to make the CLN package channel work during ELevate.
On systems where the channel has been switched off they should stand down,
regardless of registration state.

CLOS-4056: gate those actors on `is_cln_package_channel_active()`.
"""

import os


RHN_SYSTEMID = '/etc/sysconfig/rhn/systemid'
SPACEWALK_DNF_CONF = '/etc/dnf/plugins/spacewalk.conf'
SPACEWALK_YUM_CONF = '/etc/yum/pluginconf.d/spacewalk.conf'


def _plugin_explicitly_disabled(conf_path):
try:
with open(conf_path) as f:
for line in f:
stripped = line.strip().lower()
if not stripped or stripped.startswith('#') or stripped.startswith('['):
continue
if stripped.startswith('enabled') and '=' in stripped:
value = stripped.split('=', 1)[1].strip()
return value == '0'
except (OSError, IOError):
pass
return False


def is_cln_package_channel_active():
"""Return True when CLN is the active package channel for this system.

A True result means the spacewalk DNF/YUM plugin is installed, not
explicitly disabled, and the system has CLN registration state for
the plugin to authenticate with. A False result means the system is
either deregistered or has been moved to the no-auth (SWNG) scheme,
so CLN-targeting actions (channel switch, mirror pinning, version
overrides) are not meaningful and should be skipped.

This is a deliberately heuristic check - it asks "is CLN going to
serve packages here", not "is the system registered with CLN" (the
two were the same thing pre-no-auth and have since diverged).
"""
if not os.path.exists(RHN_SYSTEMID):
return False

configs = [p for p in (SPACEWALK_DNF_CONF, SPACEWALK_YUM_CONF) if os.path.exists(p)]
if not configs:
return False

for conf in configs:
if _plugin_explicitly_disabled(conf):
return False

return True
Loading
Loading