This commit is contained in:
rchac committed 2026-06-10 22:46:40 -06:00
1 parent 039bf8e146
commit 1637b612ca
6 files changed
+374 -12

No files matched your search

+9 -1
View File
@@ -49,7 +49,15 @@ sudo /opt/libreqos/src/systemd_hotfix.sh install
sudo reboot
```
El instalador del hotfix configura el repositorio APT de LibreQoS en `https://repo.libreqos.com`, instala el conjunto parchado de paquetes `systemd` de Noble y fija esos paquetes para futuras actualizaciones.
El instalador del hotfix configura el repositorio APT firmado de LibreQoS en `https://repo.libreqos.com`, instala el conjunto parchado de paquetes `systemd` de Noble y fija esos paquetes para futuras actualizaciones.
De forma predeterminada, selecciona la versión actual del hotfix desde ese repositorio.
Si Soporte de LibreQoS te indica que tu paquete instalado es anterior a v2.2, usa este comando de recuperación en su lugar:
```bash
sudo HOTFIX_PACKAGE_VERSION=255.4-1ubuntu9999+libreqos1 /opt/libreqos/src/systemd_hotfix.sh install
sudo dpkg --configure -a
sudo reboot
```
Después del reinicio, reanude la instalación:
+11 -1
View File
@@ -39,7 +39,15 @@ sudo /opt/libreqos/src/systemd_hotfix.sh install
sudo reboot
```
El instalador del hotfix configura el repositorio APT de LibreQoS en `https://repo.libreqos.com`, instala el conjunto parchado de paquetes `systemd` de Noble y fija esos paquetes para futuras actualizaciones.
El instalador del hotfix configura el repositorio APT firmado de LibreQoS en `https://repo.libreqos.com`, instala el conjunto parchado de paquetes `systemd` de Noble y fija esos paquetes para futuras actualizaciones.
De forma predeterminada, selecciona la versión actual del hotfix desde ese repositorio.
Si Soporte de LibreQoS te indica que tu paquete instalado es anterior a v2.2, usa este comando de recuperación en su lugar:
```bash
sudo HOTFIX_PACKAGE_VERSION=255.4-1ubuntu9999+libreqos1 /opt/libreqos/src/systemd_hotfix.sh install
sudo dpkg --configure -a
sudo reboot
```
Después del reinicio, reanuda la actualización y reinicia los servicios:
@@ -100,6 +108,8 @@ sudo ./systemd_hotfix.sh install
sudo reboot
```
El instalador selecciona la versión actual del hotfix desde el repositorio APT firmado de LibreQoS. Soporte de LibreQoS puede proporcionar un valor `HOTFIX_PACKAGE_VERSION` para un incidente específico.
Ejecuta los siguientes comandos para recargar los servicios de LibreQoS:
```shell
+9 -1
View File
@@ -44,7 +44,15 @@ sudo /opt/libreqos/src/systemd_hotfix.sh install
sudo reboot
```
The hotfix installer bootstraps the LibreQoS APT repo at `https://repo.libreqos.com`, installs the patched Noble `systemd` package set, and pins those packages for future updates.
The hotfix installer bootstraps the signed LibreQoS APT repo at `https://repo.libreqos.com`, installs the patched Noble `systemd` package set, and pins those packages for future updates.
By default, it selects the current hotfix version from that repo.
If LibreQoS support tells you that your installed package is older than v2.2, use this recovery command instead:
```bash
sudo HOTFIX_PACKAGE_VERSION=255.4-1ubuntu9999+libreqos1 /opt/libreqos/src/systemd_hotfix.sh install
sudo dpkg --configure -a
sudo reboot
```
After the reboot, resume the install:
+11 -1
View File
@@ -39,7 +39,15 @@ sudo /opt/libreqos/src/systemd_hotfix.sh install
sudo reboot
```
The hotfix installer bootstraps the LibreQoS APT repo at `https://repo.libreqos.com`, installs the patched Noble `systemd` package set, and pins those packages for future updates.
The hotfix installer bootstraps the signed LibreQoS APT repo at `https://repo.libreqos.com`, installs the patched Noble `systemd` package set, and pins those packages for future updates.
By default, it selects the current hotfix version from that repo.
If LibreQoS support tells you that your installed package is older than v2.2, use this recovery command instead:
```bash
sudo HOTFIX_PACKAGE_VERSION=255.4-1ubuntu9999+libreqos1 /opt/libreqos/src/systemd_hotfix.sh install
sudo dpkg --configure -a
sudo reboot
```
After the reboot, resume the upgrade and restart services:
@@ -102,6 +110,8 @@ sudo ./systemd_hotfix.sh install
sudo reboot
```
The installer selects the current hotfix version from the signed LibreQoS APT repo. LibreQoS support may provide a `HOTFIX_PACKAGE_VERSION` override for a specific incident.
Run the following commands to reload the LibreQoS services.
```shell
+92 -8
View File
@@ -11,7 +11,7 @@ HOTFIX_APT_SOURCE_PATH="${HOTFIX_APT_SOURCE_PATH:-/etc/apt/sources.list.d/libreq
HOTFIX_APT_PREFERENCES_PATH="${HOTFIX_APT_PREFERENCES_PATH:-/etc/apt/preferences.d/libreqos-systemd-hotfix}"
HOTFIX_APT_PIN_ORIGIN="${HOTFIX_APT_PIN_ORIGIN:-LibreQoS}"
HOTFIX_APT_PIN_LABEL="${HOTFIX_APT_PIN_LABEL:-LibreQoS}"
HOTFIX_PACKAGE_VERSION="${HOTFIX_PACKAGE_VERSION:-255.4-1ubuntu8.15+libreqos1}"
HOTFIX_PACKAGE_VERSION="${HOTFIX_PACKAGE_VERSION:-auto}"
SUPPORTED_UBUNTU_SYSTEMD_VERSION_GLOBS="${SUPPORTED_UBUNTU_SYSTEMD_VERSION_GLOBS:-255.4-1ubuntu8 255.4-1ubuntu8.*}"
HOTFIX_MARKER="${HOTFIX_MARKER:-/opt/libreqos/src/.systemd_hotfix_installed}"
HOTFIX_SKIP_REBOOT_PROMPT="${HOTFIX_SKIP_REBOOT_PROMPT:-0}"
@@ -58,7 +58,7 @@ Environment:
HOTFIX_APT_PREFERENCES_PATH Destination apt pin file installed on the host
HOTFIX_APT_PIN_ORIGIN Expected Release Origin field, defaults to LibreQoS
HOTFIX_APT_PIN_LABEL Expected Release Label field, defaults to LibreQoS
HOTFIX_PACKAGE_VERSION Backported package version to install
HOTFIX_PACKAGE_VERSION Backported package version to install, or auto to use the current LibreQoS repo candidate
SUPPORTED_UBUNTU_SYSTEMD_VERSION_GLOBS Space-separated stock Ubuntu version globs eligible for replacement
HOTFIX_MARKER Marker file written after install
HOTFIX_SKIP_REBOOT_PROMPT Set to 1 to suppress the reboot prompt after install
@@ -143,12 +143,88 @@ resolved_hotfix_package_names() {
}
resolved_hotfix_package_specs() {
local version="$1"
local package
while IFS= read -r package; do
printf '%s=%s\n' "$package" "$HOTFIX_PACKAGE_VERSION"
printf '%s=%s\n' "$package" "$version"
done < <(resolved_hotfix_package_names)
}
apt_candidate_version() {
local package="$1"
LC_ALL=C apt-cache policy "$package" | awk '$1 == "Candidate:" { print $2; exit }'
}
apt_candidate_pin_priority() {
local package="$1"
local version="$2"
LC_ALL=C apt-cache policy "$package" | awk -v version="$version" '
$1 == "***" && $2 == version { print $3; found = 1; exit }
$1 == version { print $2; found = 1; exit }
END { if (!found) exit 1 }
'
}
apt_candidate_has_hotfix_repo() {
local package="$1"
local version="$2"
local repo_url="${HOTFIX_REPO_URL%/}"
LC_ALL=C apt-cache policy "$package" | awk \
-v version="$version" \
-v repo_url="$repo_url" \
-v dist_component="${HOTFIX_REPO_DIST}/${HOTFIX_REPO_COMPONENT}" '
($1 == "***" && $2 == version) || ($1 == version && $2 ~ /^[0-9]+$/) {
in_version = 1
next
}
in_version && (($1 == "***" && $2 != version) || ($1 != "***" && $1 !~ /^[0-9]+$/ && $2 ~ /^[0-9]+$/)) {
in_version = 0
}
in_version && $1 ~ /^[0-9]+$/ && $2 == repo_url && $3 == dist_component {
found = 1
exit
}
END { if (!found) exit 1 }
'
}
resolve_hotfix_package_version() {
local package version priority resolved_version
if [[ "$HOTFIX_PACKAGE_VERSION" != "auto" ]]; then
[[ -n "$HOTFIX_PACKAGE_VERSION" ]] || fail "HOTFIX_PACKAGE_VERSION must not be empty."
printf '%s\n' "$HOTFIX_PACKAGE_VERSION"
return
fi
while IFS= read -r package; do
version="$(apt_candidate_version "$package")"
[[ -n "$version" && "$version" != "(none)" ]] || fail "No APT candidate is available for $package."
[[ "$version" == *"+libreqos"* ]] || fail "LibreQoS hotfix candidate is not available for $package. APT candidate is $version."
priority="$(apt_candidate_pin_priority "$package" "$version" || true)"
[[ "$priority" =~ ^[0-9]+$ ]] || fail "Unable to verify LibreQoS APT pin priority for $package=$version."
(( priority >= 1001 )) || fail "APT candidate for $package=$version is not pinned from the LibreQoS hotfix repo."
# apt-cache reports the pin on the version line; the matching source line can remain at archive priority 500.
apt_candidate_has_hotfix_repo "$package" "$version" || fail "APT candidate for $package=$version is not from $HOTFIX_REPO_URL $HOTFIX_REPO_DIST/$HOTFIX_REPO_COMPONENT."
if [[ -z "${resolved_version:-}" ]]; then
resolved_version="$version"
continue
fi
[[ "$version" == "$resolved_version" ]] || fail "Inconsistent LibreQoS hotfix package versions: expected $resolved_version but $package candidate is $version."
done < <(resolved_hotfix_package_names)
[[ -n "${resolved_version:-}" ]] || fail "No hotfix packages were selected for this host."
printf '%s\n' "$resolved_version"
}
joined_hotfix_packages() {
local packages=()
local package
@@ -282,26 +358,30 @@ bootstrap_repo() {
download_bundle() {
local workdir
local package_version
require_command apt-get
require_command apt-cache
bootstrap_repo
package_version="$(resolve_hotfix_package_version)"
workdir="$(mktemp -d /tmp/libreqos-systemd-hotfix.XXXXXX)"
(
cd "$workdir"
while IFS= read -r package; do
apt-get download "$package"
done < <(resolved_hotfix_package_specs)
done < <(resolved_hotfix_package_specs "$package_version")
)
printf '%s\n' "$workdir"
}
write_marker() {
local package_version="$1"
local package
{
printf 'installed_at=%s\n' "$(date -Iseconds)"
printf 'package_version=%s\n' "$HOTFIX_PACKAGE_VERSION"
printf 'package_version=%s\n' "$package_version"
printf 'repo_url=%s\n' "$HOTFIX_REPO_URL"
printf 'key_url=%s\n' "$HOTFIX_KEY_URL"
printf 'apt_source_path=%s\n' "$HOTFIX_APT_SOURCE_PATH"
@@ -309,7 +389,7 @@ write_marker() {
printf 'systemd_version=%s\n' "$(current_systemd_version)"
while IFS= read -r package; do
printf 'package_name=%s\n' "$package"
printf 'package_spec=%s=%s\n' "$package" "$HOTFIX_PACKAGE_VERSION"
printf 'package_spec=%s=%s\n' "$package" "$package_version"
done < <(resolved_hotfix_package_names)
} | run_as_root tee "$HOTFIX_MARKER" >/dev/null
}
@@ -338,17 +418,21 @@ offer_reboot() {
install_bundle() {
local package_specs=()
local package
local package_version
require_command apt-get
require_command apt-cache
ensure_applicable_host
bootstrap_repo
package_version="$(resolve_hotfix_package_version)"
log "Resolved LibreQoS systemd hotfix package version: $package_version"
while IFS= read -r package; do
package_specs+=("$package")
done < <(resolved_hotfix_package_specs)
done < <(resolved_hotfix_package_specs "$package_version")
run_as_root apt-get install -y "${package_specs[@]}"
write_marker
write_marker "$package_version"
log "Hotfix installed."
offer_reboot
}
+242
View File
@@ -0,0 +1,242 @@
import os
import pathlib
import subprocess
import tempfile
import textwrap
import unittest
SCRIPT = pathlib.Path(__file__).with_name("systemd_hotfix.sh")
class SystemdHotfixScriptTest(unittest.TestCase):
def run_script_function(self, function_name, extra_env=None):
with tempfile.TemporaryDirectory(prefix="lqos-hotfix-test.") as tmp:
tmp_path = pathlib.Path(tmp)
bin_path = tmp_path / "bin"
key_path = tmp_path / "key" / "libreqos.gpg"
source_path = tmp_path / "etc" / "apt" / "sources.list.d" / "libreqos-systemd-hotfix.list"
preferences_path = tmp_path / "etc" / "apt" / "preferences.d" / "libreqos-systemd-hotfix"
marker_path = tmp_path / "marker"
apt_log_path = tmp_path / "apt.log"
test_script_path = tmp_path / "systemd_hotfix_test.sh"
bin_path.mkdir()
key_path.parent.mkdir(parents=True)
source_path.parent.mkdir(parents=True)
preferences_path.parent.mkdir(parents=True)
self.write_command(
bin_path / "sudo",
"""
#!/bin/sh
exec "$@"
""",
)
self.write_command(
bin_path / "curl",
"""
#!/bin/sh
printf 'fake-keyring\\n'
""",
)
self.write_command(
bin_path / "systemctl",
"""
#!/bin/sh
case "$1" in
is-enabled) echo enabled ;;
is-active) echo active ;;
*) exit 1 ;;
esac
""",
)
self.write_command(
bin_path / "dpkg-query",
"""
#!/bin/sh
case "$*" in
*'${Version}'*' systemd'*) echo '255.4-1ubuntu8.16' ;;
*'${db:Status-Abbrev}'*' libpam-systemd'*) echo ii ;;
*'${db:Status-Abbrev}'*' libnss-systemd'*) echo ii ;;
*'${db:Status-Abbrev}'*) echo rc ;;
*) exit 1 ;;
esac
""",
)
self.write_command(
bin_path / "apt-get",
"""
#!/bin/sh
printf 'apt-get %s\\n' "$*" >> "$HOTFIX_TEST_APT_LOG"
""",
)
self.write_command(
bin_path / "apt-cache",
"""
#!/bin/sh
[ "${HOTFIX_TEST_APT_CACHE_FAIL:-0}" = "1" ] && exit 12
package="$2"
version="${HOTFIX_TEST_CANDIDATE_VERSION:-255.4-1ubuntu9999+libreqos1}"
priority="${HOTFIX_TEST_CANDIDATE_PRIORITY:-1001}"
repo_line="${HOTFIX_TEST_REPO_LINE:- 500 https://repo.libreqos.com noble/main amd64 Packages}"
case ",${HOTFIX_TEST_INCONSISTENT_PACKAGES:-}," in
*,"$package",*) version="${HOTFIX_TEST_OTHER_VERSION:-255.4-1ubuntu9999+libreqos2}" ;;
esac
if [ "${HOTFIX_TEST_NO_CANDIDATE_FOR:-}" = "$package" ]; then
version="(none)"
fi
cat <<POLICY
$package:
Installed: 255.4-1ubuntu8.16
Candidate: $version
Version table:
$version $priority
$repo_line
255.4-1ubuntu8.16 500
500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
POLICY
""",
)
env = os.environ.copy()
env.update(
{
"PATH": f"{bin_path}{os.pathsep}{env['PATH']}",
"HOTFIX_TEST_APT_LOG": str(apt_log_path),
"HOTFIX_SKIP_REBOOT_PROMPT": "1",
"HOTFIX_KEYRING_PATH": str(key_path),
"HOTFIX_APT_SOURCE_PATH": str(source_path),
"HOTFIX_APT_PREFERENCES_PATH": str(preferences_path),
"HOTFIX_MARKER": str(marker_path),
}
)
if extra_env:
env.update(extra_env)
test_script_path.write_text(SCRIPT.read_text().replace('main "$@"', ":"))
command = (
"source \"$HOTFIX_TEST_SCRIPT\"; "
"is_supported_os() { return 0; }; "
f"{function_name}"
)
env["HOTFIX_TEST_SCRIPT"] = str(test_script_path)
result = subprocess.run(
["bash", "-c", command],
cwd=SCRIPT.parent,
env=env,
text=True,
capture_output=True,
check=False,
)
apt_log = apt_log_path.read_text() if apt_log_path.exists() else ""
marker = marker_path.read_text() if marker_path.exists() else ""
return result, apt_log, marker
def run_install(self, extra_env=None):
return self.run_script_function("install_bundle", extra_env)
@staticmethod
def write_command(path, content):
path.write_text(textwrap.dedent(content).lstrip())
path.chmod(0o755)
def test_auto_resolves_consistent_libreqos_candidate(self):
result, apt_log, marker = self.run_install()
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn(
"Resolved LibreQoS systemd hotfix package version: 255.4-1ubuntu9999+libreqos1",
result.stdout,
)
self.assertIn("apt-get update", apt_log)
self.assertIn("systemd=255.4-1ubuntu9999+libreqos1", apt_log)
self.assertIn("libpam-systemd=255.4-1ubuntu9999+libreqos1", apt_log)
self.assertIn("libnss-systemd=255.4-1ubuntu9999+libreqos1", apt_log)
self.assertNotIn("libnss-resolve=", apt_log)
self.assertIn("package_version=255.4-1ubuntu9999+libreqos1", marker)
def test_auto_rejects_ubuntu_candidate(self):
result, _, _ = self.run_install(
{"HOTFIX_TEST_CANDIDATE_VERSION": "255.4-1ubuntu8.16"}
)
self.assertNotEqual(result.returncode, 0)
self.assertIn("LibreQoS hotfix candidate is not available", result.stderr)
def test_auto_rejects_missing_candidate(self):
result, _, _ = self.run_install(
{"HOTFIX_TEST_NO_CANDIDATE_FOR": "systemd"}
)
self.assertNotEqual(result.returncode, 0)
self.assertIn("No APT candidate is available for systemd", result.stderr)
def test_auto_rejects_inconsistent_package_versions(self):
result, _, _ = self.run_install(
{"HOTFIX_TEST_INCONSISTENT_PACKAGES": "udev"}
)
self.assertNotEqual(result.returncode, 0)
self.assertIn("Inconsistent LibreQoS hotfix package versions", result.stderr)
def test_auto_rejects_low_priority_candidate(self):
result, _, _ = self.run_install(
{"HOTFIX_TEST_CANDIDATE_PRIORITY": "500"}
)
self.assertNotEqual(result.returncode, 0)
self.assertIn("not pinned from the LibreQoS hotfix repo", result.stderr)
def test_auto_rejects_candidate_from_unexpected_repo(self):
result, _, _ = self.run_install(
{
"HOTFIX_TEST_REPO_LINE": (
" 500 https://example.invalid noble/main amd64 Packages"
)
}
)
self.assertNotEqual(result.returncode, 0)
self.assertIn("is not from https://repo.libreqos.com noble/main", result.stderr)
def test_auto_rejects_candidate_from_prefix_confusable_repo(self):
result, _, _ = self.run_install(
{
"HOTFIX_TEST_REPO_LINE": (
" 500 https://repo.libreqos.com.evil noble/main amd64 Packages"
)
}
)
self.assertNotEqual(result.returncode, 0)
self.assertIn("is not from https://repo.libreqos.com noble/main", result.stderr)
def test_exact_override_bypasses_candidate_resolution(self):
result, apt_log, marker = self.run_install(
{
"HOTFIX_PACKAGE_VERSION": "255.4-1ubuntu9999+libreqos1",
"HOTFIX_TEST_APT_CACHE_FAIL": "1",
}
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("systemd=255.4-1ubuntu9999+libreqos1", apt_log)
self.assertIn("package_version=255.4-1ubuntu9999+libreqos1", marker)
def test_download_uses_resolved_exact_package_specs(self):
result, apt_log, marker = self.run_script_function("download_bundle")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("apt-get update", apt_log)
self.assertIn("apt-get download systemd=255.4-1ubuntu9999+libreqos1", apt_log)
self.assertEqual("", marker)
if __name__ == "__main__":
unittest.main()