Skip to content

Commit 21de0b7

Browse files
committed
CLOS-3230: Refresh EPEL repos after the system upgrade if they remained on the old version
1 parent 63f6979 commit 21de0b7

File tree

3 files changed

+140
-31
lines changed

3 files changed

+140
-31
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from __future__ import print_function
2+
from operator import is_
3+
import os
4+
5+
from leapp.actors import Actor
6+
from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag
7+
from leapp.libraries.common.cllaunch import run_on_cloudlinux
8+
from leapp.libraries.common.backup import backup_and_remove
9+
from leapp.libraries.common.config.version import get_target_major_version
10+
11+
REPO_DIR = '/etc/yum.repos.d'
12+
EPEL_INSTALL_URL = 'https://dl.fedoraproject.org/pub/epel/epel-release-latest-{}.noarch.rpm'.format(get_target_major_version())
13+
14+
15+
class RefreshEPEL(Actor):
16+
"""
17+
Check that the EPEL repositories are correctly configured after the upgrade.
18+
19+
Depending on how the upgrade went, the EPEL repositories might still be targeting the old OS version.
20+
This actor checks that the EPEL repositories are correctly configured and if not, it will install the
21+
correct EPEL release package and refresh the repositories.
22+
"""
23+
24+
name = 'refresh_epel'
25+
# We can't depend on InstalledRPM message because by this point
26+
# the system is upgraded and the RPMs are not the same as when the data was collected.
27+
consumes = ()
28+
produces = ()
29+
tags = (ApplicationsPhaseTag.After, IPUWorkflowTag)
30+
31+
def clear_epel_repo_files(self):
32+
for repofile in os.listdir(REPO_DIR):
33+
if repofile.startswith('epel'):
34+
epel_file = os.path.join(REPO_DIR, repofile)
35+
backup_and_remove(epel_file)
36+
37+
def install_epel_release_package(self, target_url):
38+
os.system('dnf install {}'.format(target_url))
39+
self.log.info('EPEL release package installed: {}'.format(target_url))
40+
41+
@run_on_cloudlinux
42+
def process(self):
43+
target_version = int(get_target_major_version())
44+
target_epel_release = EPEL_INSTALL_URL.format(target_version)
45+
46+
# EPEL release package name is 'epel-release' and the version should match the target OS version
47+
epel_release_package = 'epel-release'
48+
49+
is_epel_installed = os.system('rpm -q {}'.format(epel_release_package)) == 0
50+
is_correct_version = os.system('rpm -q {}-{}'.format(epel_release_package, target_version)) == 0
51+
epel_files_verified = os.system('rpm -V {}'.format(epel_release_package)) == 0
52+
53+
# It's possible (although unusual) that the correct EPEL release package is installed during the upgrade,
54+
# but the EPEL repository files still point to the old OS version.
55+
# This was observed on client machines before.
56+
57+
if (is_epel_installed and not is_correct_version) or not epel_files_verified:
58+
# If the EPEL release package is installed but not the correct version, remove it
59+
# Same if the files from the package were modified
60+
os.system('rpm -e {}'.format(epel_release_package))
61+
if not is_epel_installed or not is_correct_version or not epel_files_verified:
62+
# Clear the EPEL repository files
63+
self.clear_epel_repo_files()
64+
# Install the correct EPEL release package
65+
self.install_epel_release_package(target_epel_release)
66+
# Logging for clarity
67+
self.log.info('EPEL release package installation invoked for: {}'.format(target_epel_release))

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

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
from leapp import reporting
88
from leapp.reporting import Report
99
from leapp.libraries.common.cllaunch import run_on_cloudlinux
10+
from leapp.libraries.common.backup import backup_and_remove, LEAPP_BACKUP_SUFFIX
1011

1112
REPO_DIR = '/etc/yum.repos.d'
12-
REPO_DELETE_MARKERS = ['cloudlinux', 'imunify', 'epel']
13+
# These markers are used to identify which repository files should be directly replaced with new versions.
14+
REPO_DELETE_MARKERS = ['cloudlinux', 'imunify']
15+
# These markers are used to identify which repository files should be replaced with new versions and backed up.
1316
REPO_BACKUP_MARKERS = []
17+
# This suffix is used to identify .rpmnew files that appear after package upgrade.
1418
RPMNEW = '.rpmnew'
15-
LEAPP_BACKUP_SUFFIX = '.leapp-backup'
1619

1720

1821
class ReplaceRpmnewConfigs(Actor):
@@ -30,32 +33,31 @@ def process(self):
3033
deleted_repofiles = []
3134
renamed_repofiles = []
3235

33-
for reponame in os.listdir(REPO_DIR):
34-
if any(mark in reponame for mark in REPO_DELETE_MARKERS) and RPMNEW in reponame:
35-
base_reponame = reponame[:-len(RPMNEW)]
36-
base_path = os.path.join(REPO_DIR, base_reponame)
37-
new_file_path = os.path.join(REPO_DIR, reponame)
36+
for rpmnew_filename in os.listdir(REPO_DIR):
37+
if any(mark in rpmnew_filename for mark in REPO_DELETE_MARKERS) and rpmnew_filename.endswith(RPMNEW):
38+
main_reponame = rpmnew_filename[:-len(RPMNEW)]
39+
main_file_path = os.path.join(REPO_DIR, main_reponame)
40+
rpmnew_file_path = os.path.join(REPO_DIR, rpmnew_filename)
3841

39-
os.unlink(base_path)
40-
os.rename(new_file_path, base_path)
41-
deleted_repofiles.append(base_reponame)
42-
self.log.debug('Yum repofile replaced: {}'.format(base_path))
42+
os.unlink(main_file_path)
43+
os.rename(rpmnew_file_path, main_file_path)
44+
deleted_repofiles.append(main_reponame)
45+
self.log.debug('Yum repofile replaced: {}'.format(main_file_path))
4346

44-
if any(mark in reponame for mark in REPO_BACKUP_MARKERS) and RPMNEW in reponame:
45-
base_reponame = reponame[:-len(RPMNEW)]
46-
base_path = os.path.join(REPO_DIR, base_reponame)
47-
new_file_path = os.path.join(REPO_DIR, reponame)
48-
backup_path = os.path.join(REPO_DIR, base_reponame + LEAPP_BACKUP_SUFFIX)
47+
if any(mark in rpmnew_filename for mark in REPO_BACKUP_MARKERS) and rpmnew_filename.endswith(RPMNEW):
48+
main_reponame = rpmnew_filename[:-len(RPMNEW)]
49+
main_file_path = os.path.join(REPO_DIR, main_reponame)
50+
rpmnew_file_path = os.path.join(REPO_DIR, rpmnew_filename)
4951

50-
os.rename(base_path, backup_path)
51-
os.rename(new_file_path, base_path)
52-
renamed_repofiles.append(base_reponame)
53-
self.log.debug('Yum repofile replaced with backup: {}'.format(base_path))
52+
backup_and_remove(main_file_path)
53+
os.rename(rpmnew_file_path, main_file_path)
54+
renamed_repofiles.append(main_reponame)
55+
self.log.debug('Yum repofile replaced with backup: {}'.format(main_file_path))
5456

5557
# Disable any old repositories.
56-
for reponame in os.listdir(REPO_DIR):
57-
if LEAPP_BACKUP_SUFFIX in reponame:
58-
repofile_path = os.path.join(REPO_DIR, reponame)
58+
for repofile_name in os.listdir(REPO_DIR):
59+
if LEAPP_BACKUP_SUFFIX in repofile_name:
60+
repofile_path = os.path.join(REPO_DIR, repofile_name)
5961
for line in fileinput.input(repofile_path, inplace=True):
6062
if line.startswith('enabled'):
6163
print("enabled = 0")
@@ -66,7 +68,7 @@ def process(self):
6668
deleted_string = '\n'.join(['{}'.format(repofile_name) for repofile_name in deleted_repofiles])
6769
replaced_string = '\n'.join(['{}'.format(repofile_name) for repofile_name in renamed_repofiles])
6870
reporting.create_report([
69-
reporting.Title('CloudLinux repository config files replaced by updated versions'),
71+
reporting.Title('Repository config files replaced by updated versions'),
7072
reporting.Summary(
7173
'One or more RPM repository configuration files '
7274
'have been replaced with new versions provided by the upgraded packages. '

repos/system_upgrade/cloudlinux/libraries/backup.py

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
"""
2+
Backup functionality for CloudLinux system upgrade process.
3+
4+
This module provides utilities for backing up and restoring system configuration files
5+
during the CloudLinux upgrade process. It includes functions for:
6+
- Backing up files to a specified backup directory
7+
- Creating in-place backups with .leapp-backup suffix
8+
- Backing up and removing files
9+
- Restoring files from backups
10+
11+
Typically used in other CloudLinux upgrade actors to ensure that some specific configuration files
12+
are preserved and can be restored in case of issues during the upgrade process.
13+
"""
14+
115
import os
216
import shutil
317
from leapp.libraries.stdlib import api
@@ -10,6 +24,28 @@
1024
]
1125

1226
BACKUP_DIR = "/var/lib/leapp/cl_backup"
27+
LEAPP_BACKUP_SUFFIX = ".leapp-backup"
28+
29+
30+
def backup_and_remove(path):
31+
# type: (str) -> None
32+
"""
33+
Backup the file in-place and remove the original file.
34+
35+
:param path: Path of the file to backup and remove.
36+
"""
37+
backup_file_in_place(path)
38+
os.unlink(path)
39+
40+
41+
def backup_file_in_place(path):
42+
# type: (str) -> None
43+
"""
44+
Backup file in place, creating a copy of it with the same name and .leapp-backup suffix.
45+
46+
:param path: Path of the file to backup.
47+
"""
48+
backup_file(path, path + LEAPP_BACKUP_SUFFIX)
1349

1450

1551
def backup_file(source, destination, backup_directory=""):
@@ -19,14 +55,18 @@ def backup_file(source, destination, backup_directory=""):
1955
2056
:param source: Path of the file to backup.
2157
:param destination: Destination name of a file in the backup directory.
22-
:param dir: Backup directory override, defaults to None
58+
If an absolute path is provided, it will be used as the destination path.
59+
:param backup_directory: Backup directory override, defaults to None
2360
"""
24-
if not backup_directory:
25-
backup_directory = BACKUP_DIR
26-
if not os.path.isdir(backup_directory):
27-
os.makedirs(backup_directory)
28-
29-
dest_path = os.path.join(backup_directory, destination)
61+
# If destination is an absolute path, use it as the destination path
62+
if os.path.isabs(destination):
63+
dest_path = destination
64+
else:
65+
if not backup_directory:
66+
backup_directory = BACKUP_DIR
67+
if not os.path.isdir(backup_directory):
68+
os.makedirs(backup_directory)
69+
dest_path = os.path.join(backup_directory, destination)
3070

3171
api.current_logger().debug('Backing up file: {} to {}'.format(source, dest_path))
3272
shutil.copy(source, dest_path)

0 commit comments

Comments
 (0)