Add detection for ostree-based systems and warn users about losing changes

On ostree-based systems, users can use dnf to customize the
environment but those changes will be lost at the next ostree-based
image update.  If you want to retain changes between ostree-updates
you need to make use of rpm-ostree right now.

Signed-off-by: David Cantrell <dcantrell@redhat.com>
This commit is contained in:
David Cantrell 2024-02-15 14:03:32 -05:00 committed by kolage
parent e3cb438c0f
commit 5c050ba232
2 changed files with 40 additions and 0 deletions

View File

@ -214,6 +214,15 @@ class BaseCli(dnf.Base):
elif 'test' in self.conf.tsflags:
logger.info(_("{prog} will only download packages, install gpg keys, and check the "
"transaction.").format(prog=dnf.util.MAIN_PROG_UPPER))
if dnf.util.is_container():
_container_msg = _("""
*** This system is managed with ostree. Changes to the system
*** made with dnf will be lost with the next ostree-based update.
*** If you do not want to lose these changes, use 'rpm-ostree'.
""")
logger.info(_container_msg)
raise CliError(_("Operation aborted."))
if self._promptWanted():
if self.conf.assumeno or not self.output.userconfirm():
raise CliError(_("Operation aborted."))

View File

@ -33,11 +33,13 @@ import errno
import functools
import hawkey
import itertools
import json
import locale
import logging
import os
import pwd
import shutil
import subprocess
import sys
import tempfile
import time
@ -639,3 +641,32 @@ def _is_file_pattern_present(specs):
if subj._filename_pattern:
return True
return False
def is_container():
"""Returns true is the system is managed as an immutable container,
false otherwise. If msg is True, a warning message is displayed
for the user.
"""
bootc = '/usr/bin/bootc'
ostree = '/sysroot/ostree'
if os.path.isfile(bootc) and os.access(bootc, os.X_OK):
p = subprocess.Popen([bootc, "status", "--json"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = p.communicate()
if p.returncode == 0:
# check the output of 'bootc status'
j = json.loads(out)
# XXX: the API from bootc status is evolving
status = j.get("status", "")
kind = j.get("kind", "")
if kind.lower() == "bootchost" and bool(status.get("isContainer", None)):
return True
elif os.path.isdir(ostree):
return True
return False