Add support for transient transactions
Resolves: RHEL-70917
This commit is contained in:
parent
a0ecbb0097
commit
48402e5143
181
0039-Add-support-for-transient.patch
Normal file
181
0039-Add-support-for-transient.patch
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
From e236290f4aec12ad9b2e5cdfa48ec8e3172bb89c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Evan Goode <mail@evangoo.de>
|
||||||
|
Date: Thu, 7 Nov 2024 02:31:25 +0000
|
||||||
|
Subject: [PATCH 39/44] Add support for --transient
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Upstream commit: 6091f3fccea988208ca417a504569947e4c99263
|
||||||
|
|
||||||
|
Adds support for the --transient option on all transactions. Passing
|
||||||
|
--transient on a bootc system will call `bootc usr-overlay` to create a
|
||||||
|
transient writeable /usr and continue the transaction.
|
||||||
|
|
||||||
|
Specifying --transient on a non-bootc system will throw an error; we
|
||||||
|
don't want to mislead users to thinking this feature works on non-bootc
|
||||||
|
systems.
|
||||||
|
|
||||||
|
If --transient is not specified and the bootc system is in a locked
|
||||||
|
state, the operation will be aborted and a message will be printed
|
||||||
|
suggesting to try again with --transient.
|
||||||
|
|
||||||
|
Resolves: https://issues.redhat.com/browse/RHEL-70917
|
||||||
|
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||||||
|
---
|
||||||
|
dnf/cli/cli.py | 40 ++++++++++++++++++++++++++++++---------
|
||||||
|
dnf/cli/option_parser.py | 3 +++
|
||||||
|
dnf/conf/config.py | 2 +-
|
||||||
|
dnf/util.py | 41 +++++++++++++++++++++++++++++-----------
|
||||||
|
4 files changed, 65 insertions(+), 21 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/dnf/cli/cli.py b/dnf/cli/cli.py
|
||||||
|
index 3dc08d616..33fe20aab 100644
|
||||||
|
--- a/dnf/cli/cli.py
|
||||||
|
+++ b/dnf/cli/cli.py
|
||||||
|
@@ -205,28 +205,50 @@ class BaseCli(dnf.Base):
|
||||||
|
else:
|
||||||
|
self.output.reportDownloadSize(install_pkgs, install_only)
|
||||||
|
|
||||||
|
+ bootc_unlock_requested = False
|
||||||
|
+
|
||||||
|
if trans or self._moduleContainer.isChanged() or \
|
||||||
|
(self._history and (self._history.group or self._history.env)):
|
||||||
|
# confirm with user
|
||||||
|
if self.conf.downloadonly:
|
||||||
|
logger.info(_("{prog} will only download packages for the transaction.").format(
|
||||||
|
prog=dnf.util.MAIN_PROG_UPPER))
|
||||||
|
+
|
||||||
|
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_bootc_host() and \
|
||||||
|
- os.path.realpath(self.conf.installroot) == "/" and \
|
||||||
|
- not self.conf.downloadonly:
|
||||||
|
- _bootc_host_msg = _("""
|
||||||
|
-*** Error: system is configured to be read-only; for more
|
||||||
|
-*** information run `bootc --help`.
|
||||||
|
-""")
|
||||||
|
- logger.info(_bootc_host_msg)
|
||||||
|
- raise CliError(_("Operation aborted."))
|
||||||
|
+
|
||||||
|
+ is_bootc_transaction = dnf.util._is_bootc_host() and \
|
||||||
|
+ os.path.realpath(self.conf.installroot) == "/" and \
|
||||||
|
+ not self.conf.downloadonly
|
||||||
|
+
|
||||||
|
+ # Handle bootc transactions. `--transient` must be specified if
|
||||||
|
+ # /usr is not already writeable.
|
||||||
|
+ if is_bootc_transaction:
|
||||||
|
+ if self.conf.persistence == "persist":
|
||||||
|
+ logger.info(_("Persistent transactions aren't supported on bootc systems."))
|
||||||
|
+ raise CliError(_("Operation aborted."))
|
||||||
|
+ assert self.conf.persistence in ("auto", "transient")
|
||||||
|
+ if not dnf.util._is_bootc_unlocked():
|
||||||
|
+ if self.conf.persistence == "auto":
|
||||||
|
+ logger.info(_("This bootc system is configured to be read-only. Pass --transient to "
|
||||||
|
+ "perform this and subsequent transactions in a transient overlay which "
|
||||||
|
+ "will reset when the system reboots."))
|
||||||
|
+ raise CliError(_("Operation aborted."))
|
||||||
|
+ assert self.conf.persistence == "transient"
|
||||||
|
+ logger.info(_("A transient overlay will be created on /usr that will be discarded on reboot. "
|
||||||
|
+ "Keep in mind that changes to /etc and /var will still persist, and packages "
|
||||||
|
+ "commonly modify these directories."))
|
||||||
|
+ bootc_unlock_requested = True
|
||||||
|
+ elif self.conf.persistence == "transient":
|
||||||
|
+ raise CliError(_("Transient transactions are only supported on bootc systems."))
|
||||||
|
|
||||||
|
if self._promptWanted():
|
||||||
|
if self.conf.assumeno or not self.output.userconfirm():
|
||||||
|
raise CliError(_("Operation aborted."))
|
||||||
|
+
|
||||||
|
+ if bootc_unlock_requested:
|
||||||
|
+ dnf.util._bootc_unlock()
|
||||||
|
else:
|
||||||
|
logger.info(_('Nothing to do.'))
|
||||||
|
return
|
||||||
|
diff --git a/dnf/cli/option_parser.py b/dnf/cli/option_parser.py
|
||||||
|
index 41ff16451..66e69cc98 100644
|
||||||
|
--- a/dnf/cli/option_parser.py
|
||||||
|
+++ b/dnf/cli/option_parser.py
|
||||||
|
@@ -320,6 +320,9 @@ class OptionParser(argparse.ArgumentParser):
|
||||||
|
general_grp.add_argument("--downloadonly", dest="downloadonly",
|
||||||
|
action="store_true", default=False,
|
||||||
|
help=_("only download packages"))
|
||||||
|
+ general_grp.add_argument("--transient", dest="persistence",
|
||||||
|
+ action="store_const", const="transient", default=None,
|
||||||
|
+ help=_("Use a transient overlay which will reset on reboot"))
|
||||||
|
general_grp.add_argument("--comment", dest="comment", default=None,
|
||||||
|
help=_("add a comment to transaction"))
|
||||||
|
# Updateinfo options...
|
||||||
|
diff --git a/dnf/conf/config.py b/dnf/conf/config.py
|
||||||
|
index 32516d1a8..ed6daeb2d 100644
|
||||||
|
--- a/dnf/conf/config.py
|
||||||
|
+++ b/dnf/conf/config.py
|
||||||
|
@@ -342,7 +342,7 @@ class MainConf(BaseConfig):
|
||||||
|
'best', 'assumeyes', 'assumeno', 'clean_requirements_on_remove', 'gpgcheck',
|
||||||
|
'showdupesfromrepos', 'plugins', 'ip_resolve',
|
||||||
|
'rpmverbosity', 'disable_excludes', 'color',
|
||||||
|
- 'downloadonly', 'exclude', 'excludepkgs', 'skip_broken',
|
||||||
|
+ 'downloadonly', 'persistence', 'exclude', 'excludepkgs', 'skip_broken',
|
||||||
|
'tsflags', 'arch', 'basearch', 'ignorearch', 'cacheonly', 'comment']
|
||||||
|
|
||||||
|
for name in config_args:
|
||||||
|
diff --git a/dnf/util.py b/dnf/util.py
|
||||||
|
index e8f587a03..f22e3901b 100644
|
||||||
|
--- a/dnf/util.py
|
||||||
|
+++ b/dnf/util.py
|
||||||
|
@@ -38,6 +38,7 @@ import logging
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
|
import shutil
|
||||||
|
+import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
@@ -634,14 +635,32 @@ def _name_unset_wrapper(input_name):
|
||||||
|
|
||||||
|
|
||||||
|
def _is_bootc_host():
|
||||||
|
- """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.
|
||||||
|
- """
|
||||||
|
- ostree_booted = '/run/ostree-booted'
|
||||||
|
- usr = '/usr/'
|
||||||
|
- # Check if usr is writtable and we are in a running ostree system.
|
||||||
|
- # We want this code to return true only when the system is in locked state. If someone ran
|
||||||
|
- # bootc overlay or ostree admin unlock we would want normal DNF path to be ran as it will be
|
||||||
|
- # temporary changes (until reboot).
|
||||||
|
- return os.path.isfile(ostree_booted) and not os.access(usr, os.W_OK)
|
||||||
|
+ """Returns true is the system is managed as an immutable container, false
|
||||||
|
+ otherwise."""
|
||||||
|
+ ostree_booted = "/run/ostree-booted"
|
||||||
|
+ return os.path.isfile(ostree_booted)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def _is_bootc_unlocked():
|
||||||
|
+ """Check whether /usr is writeable, e.g. if we are in a normal mutable
|
||||||
|
+ system or if we are in a bootc after `bootc usr-overlay` or `ostree admin
|
||||||
|
+ unlock` was run."""
|
||||||
|
+ usr = "/usr"
|
||||||
|
+ return os.access(usr, os.W_OK)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def _bootc_unlock():
|
||||||
|
+ """Set up a writeable overlay on bootc systems."""
|
||||||
|
+
|
||||||
|
+ if _is_bootc_unlocked():
|
||||||
|
+ return
|
||||||
|
+
|
||||||
|
+ unlock_command = ["bootc", "usr-overlay"]
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ completed_process = subprocess.run(unlock_command, text=True)
|
||||||
|
+ completed_process.check_returncode()
|
||||||
|
+ except FileNotFoundError:
|
||||||
|
+ raise dnf.exceptions.Error(_("bootc command not found. Is this a bootc system?"))
|
||||||
|
+ except subprocess.CalledProcessError:
|
||||||
|
+ raise dnf.exceptions.Error(_("Failed to unlock system: %s", completed_process.stderr))
|
||||||
|
--
|
||||||
|
2.48.1
|
||||||
|
|
74
0040-bootc-Document-transient-and-persistence.patch
Normal file
74
0040-bootc-Document-transient-and-persistence.patch
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
From ec5cbd19adc6f384923e95d42357f23696b3c950 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Evan Goode <mail@evangoo.de>
|
||||||
|
Date: Tue, 17 Dec 2024 18:58:32 +0000
|
||||||
|
Subject: [PATCH 40/44] bootc: Document `--transient` and `persistence`
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Upstream commit: 80a62d89ba3c00f4e0bd3fea995d04ccf9ba8098
|
||||||
|
|
||||||
|
Documents the new `--transient` command-line argument and `persistence`
|
||||||
|
configuration option. I tried to use a table for listing the valid
|
||||||
|
options for `persistence`, but RST does not automatically wrap table
|
||||||
|
cells containing long lines, so a list was much easier.
|
||||||
|
|
||||||
|
Resolves: https://issues.redhat.com/browse/RHEL-70917
|
||||||
|
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||||||
|
---
|
||||||
|
doc/command_ref.rst | 9 +++++++++
|
||||||
|
doc/conf_ref.rst | 11 +++++++++++
|
||||||
|
2 files changed, 20 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/doc/command_ref.rst b/doc/command_ref.rst
|
||||||
|
index 75ded68cd..8b55d5a76 100644
|
||||||
|
--- a/doc/command_ref.rst
|
||||||
|
+++ b/doc/command_ref.rst
|
||||||
|
@@ -389,6 +389,11 @@ Options
|
||||||
|
``--showduplicates``
|
||||||
|
Show duplicate packages in repositories. Applicable for the list and search commands.
|
||||||
|
|
||||||
|
+.. _transient_option-label:
|
||||||
|
+
|
||||||
|
+``--transient``
|
||||||
|
+ Applicable only on bootc (bootable containers) systems. Perform transactions using a transient overlay which will be lost on the next reboot. See also the :ref:`persistence <persistence-label>` configuration option.
|
||||||
|
+
|
||||||
|
.. _verbose_options-label:
|
||||||
|
|
||||||
|
``-v, --verbose``
|
||||||
|
@@ -708,6 +713,10 @@ transactions and act according to this information (assuming the
|
||||||
|
which specifies a transaction by a package which it manipulated. When no
|
||||||
|
transaction is specified, list all known transactions.
|
||||||
|
|
||||||
|
+ Note that transient transactions (see :ref:`--transient
|
||||||
|
+ <transient_option-label>`) will be listed even though they do not make
|
||||||
|
+ persistent changes to files under ``/usr`` or to the RPM database.
|
||||||
|
+
|
||||||
|
The "Action(s)" column lists each type of action taken in the transaction. The possible values are:
|
||||||
|
|
||||||
|
* Install (I): a new package was installed on the system
|
||||||
|
diff --git a/doc/conf_ref.rst b/doc/conf_ref.rst
|
||||||
|
index 42a9a37e5..a34e355b6 100644
|
||||||
|
--- a/doc/conf_ref.rst
|
||||||
|
+++ b/doc/conf_ref.rst
|
||||||
|
@@ -430,6 +430,17 @@ configuration file by your distribution to override the DNF defaults.
|
||||||
|
|
||||||
|
Directory where DNF stores its persistent data between runs. Default is ``"/var/lib/dnf"``.
|
||||||
|
|
||||||
|
+.. _persistence-label:
|
||||||
|
+
|
||||||
|
+``persistence``
|
||||||
|
+ :ref:`string <string-label>`
|
||||||
|
+
|
||||||
|
+ Whether changes should persist across system reboots. Default is ``auto``. Passing :ref:`--transient <transient_option-label>` will override this setting to ``transient``. Valid values are:
|
||||||
|
+
|
||||||
|
+ * ``auto``: Changes will persist across reboots, unless the target is a running bootc system and the system is already in an unlocked state (i.e. ``/usr`` is writable).
|
||||||
|
+ * ``transient``: Changes will be lost on the next reboot. Only applicable on bootc systems. Beware that changes to ``/etc`` and ``/var`` will persist, depending on the configuration of your bootc system. See also https://containers.github.io/bootc/man/bootc-usr-overlay.html.
|
||||||
|
+ * ``persist``: Changes will persist across reboots.
|
||||||
|
+
|
||||||
|
.. _pluginconfpath-label:
|
||||||
|
|
||||||
|
``pluginconfpath``
|
||||||
|
--
|
||||||
|
2.48.1
|
||||||
|
|
166
0041-bootc-Use-ostree-GObject-API-to-get-deployment-statu.patch
Normal file
166
0041-bootc-Use-ostree-GObject-API-to-get-deployment-statu.patch
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
From 5a5572b8adc335075cdae321ad1447e1b8bd8760 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Evan Goode <mail@evangoo.de>
|
||||||
|
Date: Wed, 15 Jan 2025 21:43:58 +0000
|
||||||
|
Subject: [PATCH 41/44] bootc: Use ostree GObject API to get deployment status
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Upstream commit: f3abee56452e40ce475f714666c3a16426759c96
|
||||||
|
|
||||||
|
Using libostree gives us more detail about the current state of the
|
||||||
|
deployment than only checking whether /usr is writable.
|
||||||
|
|
||||||
|
Resolves: https://issues.redhat.com/browse/RHEL-70917
|
||||||
|
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||||||
|
---
|
||||||
|
dnf/cli/cli.py | 13 ++++----
|
||||||
|
dnf/util.py | 80 +++++++++++++++++++++++++++++++++++---------------
|
||||||
|
2 files changed, 65 insertions(+), 28 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/dnf/cli/cli.py b/dnf/cli/cli.py
|
||||||
|
index 33fe20aab..e7ca86ba8 100644
|
||||||
|
--- a/dnf/cli/cli.py
|
||||||
|
+++ b/dnf/cli/cli.py
|
||||||
|
@@ -218,18 +218,22 @@ class BaseCli(dnf.Base):
|
||||||
|
logger.info(_("{prog} will only download packages, install gpg keys, and check the "
|
||||||
|
"transaction.").format(prog=dnf.util.MAIN_PROG_UPPER))
|
||||||
|
|
||||||
|
- is_bootc_transaction = dnf.util._is_bootc_host() and \
|
||||||
|
+ is_bootc_transaction = dnf.util._Bootc.is_bootc_host() and \
|
||||||
|
os.path.realpath(self.conf.installroot) == "/" and \
|
||||||
|
not self.conf.downloadonly
|
||||||
|
|
||||||
|
# Handle bootc transactions. `--transient` must be specified if
|
||||||
|
# /usr is not already writeable.
|
||||||
|
+ bootc = None
|
||||||
|
if is_bootc_transaction:
|
||||||
|
if self.conf.persistence == "persist":
|
||||||
|
logger.info(_("Persistent transactions aren't supported on bootc systems."))
|
||||||
|
raise CliError(_("Operation aborted."))
|
||||||
|
assert self.conf.persistence in ("auto", "transient")
|
||||||
|
- if not dnf.util._is_bootc_unlocked():
|
||||||
|
+
|
||||||
|
+ bootc = dnf.util._Bootc()
|
||||||
|
+
|
||||||
|
+ if not bootc.is_unlocked():
|
||||||
|
if self.conf.persistence == "auto":
|
||||||
|
logger.info(_("This bootc system is configured to be read-only. Pass --transient to "
|
||||||
|
"perform this and subsequent transactions in a transient overlay which "
|
||||||
|
@@ -239,7 +243,6 @@ class BaseCli(dnf.Base):
|
||||||
|
logger.info(_("A transient overlay will be created on /usr that will be discarded on reboot. "
|
||||||
|
"Keep in mind that changes to /etc and /var will still persist, and packages "
|
||||||
|
"commonly modify these directories."))
|
||||||
|
- bootc_unlock_requested = True
|
||||||
|
elif self.conf.persistence == "transient":
|
||||||
|
raise CliError(_("Transient transactions are only supported on bootc systems."))
|
||||||
|
|
||||||
|
@@ -247,8 +250,8 @@ class BaseCli(dnf.Base):
|
||||||
|
if self.conf.assumeno or not self.output.userconfirm():
|
||||||
|
raise CliError(_("Operation aborted."))
|
||||||
|
|
||||||
|
- if bootc_unlock_requested:
|
||||||
|
- dnf.util._bootc_unlock()
|
||||||
|
+ if bootc:
|
||||||
|
+ bootc.unlock_and_prepare()
|
||||||
|
else:
|
||||||
|
logger.info(_('Nothing to do.'))
|
||||||
|
return
|
||||||
|
diff --git a/dnf/util.py b/dnf/util.py
|
||||||
|
index f22e3901b..994fddafc 100644
|
||||||
|
--- a/dnf/util.py
|
||||||
|
+++ b/dnf/util.py
|
||||||
|
@@ -634,33 +634,67 @@ def _name_unset_wrapper(input_name):
|
||||||
|
return input_name if input_name else _("<name-unset>")
|
||||||
|
|
||||||
|
|
||||||
|
-def _is_bootc_host():
|
||||||
|
- """Returns true is the system is managed as an immutable container, false
|
||||||
|
- otherwise."""
|
||||||
|
- ostree_booted = "/run/ostree-booted"
|
||||||
|
- return os.path.isfile(ostree_booted)
|
||||||
|
+class _Bootc:
|
||||||
|
+ usr = "/usr"
|
||||||
|
|
||||||
|
+ def __init__(self):
|
||||||
|
+ if not self.is_bootc_host():
|
||||||
|
+ raise RuntimeError(_("Not running on a bootc system."))
|
||||||
|
|
||||||
|
-def _is_bootc_unlocked():
|
||||||
|
- """Check whether /usr is writeable, e.g. if we are in a normal mutable
|
||||||
|
- system or if we are in a bootc after `bootc usr-overlay` or `ostree admin
|
||||||
|
- unlock` was run."""
|
||||||
|
- usr = "/usr"
|
||||||
|
- return os.access(usr, os.W_OK)
|
||||||
|
+ import gi
|
||||||
|
+ self._gi = gi
|
||||||
|
|
||||||
|
+ gi.require_version("OSTree", "1.0")
|
||||||
|
+ from gi.repository import OSTree
|
||||||
|
|
||||||
|
-def _bootc_unlock():
|
||||||
|
- """Set up a writeable overlay on bootc systems."""
|
||||||
|
+ self._OSTree = OSTree
|
||||||
|
|
||||||
|
- if _is_bootc_unlocked():
|
||||||
|
- return
|
||||||
|
+ self._sysroot = self._OSTree.Sysroot.new_default()
|
||||||
|
+ assert self._sysroot.load(None)
|
||||||
|
|
||||||
|
- unlock_command = ["bootc", "usr-overlay"]
|
||||||
|
+ self._booted_deployment = self._sysroot.require_booted_deployment()
|
||||||
|
+ assert self._booted_deployment is not None
|
||||||
|
|
||||||
|
- try:
|
||||||
|
- completed_process = subprocess.run(unlock_command, text=True)
|
||||||
|
- completed_process.check_returncode()
|
||||||
|
- except FileNotFoundError:
|
||||||
|
- raise dnf.exceptions.Error(_("bootc command not found. Is this a bootc system?"))
|
||||||
|
- except subprocess.CalledProcessError:
|
||||||
|
- raise dnf.exceptions.Error(_("Failed to unlock system: %s", completed_process.stderr))
|
||||||
|
+ @staticmethod
|
||||||
|
+ def is_bootc_host():
|
||||||
|
+ """Returns true is the system is managed as an immutable container, false
|
||||||
|
+ otherwise."""
|
||||||
|
+ ostree_booted = "/run/ostree-booted"
|
||||||
|
+ return os.path.isfile(ostree_booted)
|
||||||
|
+
|
||||||
|
+ def _get_unlocked_state(self):
|
||||||
|
+ return self._booted_deployment.get_unlocked()
|
||||||
|
+
|
||||||
|
+ def is_unlocked(self):
|
||||||
|
+ return self._get_unlocked_state() != self._OSTree.DeploymentUnlockedState.NONE
|
||||||
|
+
|
||||||
|
+ def unlock_and_prepare(self):
|
||||||
|
+ """Set up a writeable overlay on bootc systems."""
|
||||||
|
+
|
||||||
|
+ bootc_unlocked_state = self._get_unlocked_state()
|
||||||
|
+
|
||||||
|
+ valid_bootc_unlocked_states = (
|
||||||
|
+ self._OSTree.DeploymentUnlockedState.NONE,
|
||||||
|
+ self._OSTree.DeploymentUnlockedState.DEVELOPMENT,
|
||||||
|
+ # self._OSTree.DeploymentUnlockedState.TRANSIENT,
|
||||||
|
+ # self._OSTree.DeploymentUnlockedState.HOTFIX,
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ if bootc_unlocked_state not in valid_bootc_unlocked_states:
|
||||||
|
+ raise ValueError(_("Unhandled bootc unlocked state: %s") % bootc_unlocked_state.value_nick)
|
||||||
|
+
|
||||||
|
+ if bootc_unlocked_state == self._OSTree.DeploymentUnlockedState.DEVELOPMENT:
|
||||||
|
+ # System is already unlocked.
|
||||||
|
+ pass
|
||||||
|
+ elif bootc_unlocked_state == self._OSTree.DeploymentUnlockedState.NONE:
|
||||||
|
+ unlock_command = ["ostree", "admin", "unlock"]
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ completed_process = subprocess.run(unlock_command, text=True)
|
||||||
|
+ completed_process.check_returncode()
|
||||||
|
+ except FileNotFoundError:
|
||||||
|
+ raise dnf.exceptions.Error(_("ostree command not found. Is this a bootc system?"))
|
||||||
|
+ except subprocess.CalledProcessError:
|
||||||
|
+ raise dnf.exceptions.Error(_("Failed to unlock system: %s", completed_process.stderr))
|
||||||
|
+
|
||||||
|
+ assert os.access(self.usr, os.W_OK)
|
||||||
|
--
|
||||||
|
2.48.1
|
||||||
|
|
237
0042-bootc-Re-locking-use-ostree-admin-unlock-transient.patch
Normal file
237
0042-bootc-Re-locking-use-ostree-admin-unlock-transient.patch
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
From 7e0180ad97a677e6701031f13069c20beec1d8ff Mon Sep 17 00:00:00 2001
|
||||||
|
From: Evan Goode <mail@evangoo.de>
|
||||||
|
Date: Thu, 16 Jan 2025 14:06:26 -0500
|
||||||
|
Subject: [PATCH 42/44] bootc: "Re-locking": use ostree admin unlock
|
||||||
|
--transient
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Upstream commit: fa47a256ae7add2ce1c99ae8bedce7216001f396
|
||||||
|
|
||||||
|
To keep /usr read-only after DNF is finished with a transient
|
||||||
|
transaction, we call `ostree admin unlock --transient` to mount the /usr
|
||||||
|
overlay as read-only by default. Then, we create a private mount
|
||||||
|
namespace for DNF and its child processes and remount the /usr overlayfs
|
||||||
|
as read/write in the private mountns.
|
||||||
|
|
||||||
|
os.unshare is unfortunately only available in Python >= 3.12, so we have
|
||||||
|
to call libc.unshare via Python ctypes here and hardcode the CLONE_NEWNS
|
||||||
|
flag that we need to pass.
|
||||||
|
|
||||||
|
Resolves: https://issues.redhat.com/browse/RHEL-70917
|
||||||
|
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||||||
|
---
|
||||||
|
dnf/cli/cli.py | 33 ++++++++++---------
|
||||||
|
dnf/util.py | 86 ++++++++++++++++++++++++++++++++++++++------------
|
||||||
|
2 files changed, 83 insertions(+), 36 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/dnf/cli/cli.py b/dnf/cli/cli.py
|
||||||
|
index e7ca86ba8..23170a82b 100644
|
||||||
|
--- a/dnf/cli/cli.py
|
||||||
|
+++ b/dnf/cli/cli.py
|
||||||
|
@@ -205,8 +205,6 @@ class BaseCli(dnf.Base):
|
||||||
|
else:
|
||||||
|
self.output.reportDownloadSize(install_pkgs, install_only)
|
||||||
|
|
||||||
|
- bootc_unlock_requested = False
|
||||||
|
-
|
||||||
|
if trans or self._moduleContainer.isChanged() or \
|
||||||
|
(self._history and (self._history.group or self._history.env)):
|
||||||
|
# confirm with user
|
||||||
|
@@ -218,40 +216,45 @@ class BaseCli(dnf.Base):
|
||||||
|
logger.info(_("{prog} will only download packages, install gpg keys, and check the "
|
||||||
|
"transaction.").format(prog=dnf.util.MAIN_PROG_UPPER))
|
||||||
|
|
||||||
|
- is_bootc_transaction = dnf.util._Bootc.is_bootc_host() and \
|
||||||
|
+ is_bootc_transaction = dnf.util._BootcSystem.is_bootc_system() and \
|
||||||
|
os.path.realpath(self.conf.installroot) == "/" and \
|
||||||
|
not self.conf.downloadonly
|
||||||
|
|
||||||
|
# Handle bootc transactions. `--transient` must be specified if
|
||||||
|
# /usr is not already writeable.
|
||||||
|
- bootc = None
|
||||||
|
+ bootc_system = None
|
||||||
|
if is_bootc_transaction:
|
||||||
|
if self.conf.persistence == "persist":
|
||||||
|
logger.info(_("Persistent transactions aren't supported on bootc systems."))
|
||||||
|
raise CliError(_("Operation aborted."))
|
||||||
|
assert self.conf.persistence in ("auto", "transient")
|
||||||
|
|
||||||
|
- bootc = dnf.util._Bootc()
|
||||||
|
+ bootc_system = dnf.util._BootcSystem()
|
||||||
|
|
||||||
|
- if not bootc.is_unlocked():
|
||||||
|
+ if not bootc_system.is_writable():
|
||||||
|
if self.conf.persistence == "auto":
|
||||||
|
logger.info(_("This bootc system is configured to be read-only. Pass --transient to "
|
||||||
|
- "perform this and subsequent transactions in a transient overlay which "
|
||||||
|
- "will reset when the system reboots."))
|
||||||
|
+ "perform this transaction in a transient overlay which will reset when "
|
||||||
|
+ "the system reboots."))
|
||||||
|
raise CliError(_("Operation aborted."))
|
||||||
|
assert self.conf.persistence == "transient"
|
||||||
|
- logger.info(_("A transient overlay will be created on /usr that will be discarded on reboot. "
|
||||||
|
- "Keep in mind that changes to /etc and /var will still persist, and packages "
|
||||||
|
- "commonly modify these directories."))
|
||||||
|
- elif self.conf.persistence == "transient":
|
||||||
|
- raise CliError(_("Transient transactions are only supported on bootc systems."))
|
||||||
|
+ if not bootc_system.is_unlocked_transient():
|
||||||
|
+ # Only tell the user about the transient overlay if
|
||||||
|
+ # it's not already in place
|
||||||
|
+ logger.info(_("A transient overlay will be created on /usr that will be discarded on reboot. "
|
||||||
|
+ "Keep in mind that changes to /etc and /var will still persist, and packages "
|
||||||
|
+ "commonly modify these directories."))
|
||||||
|
+ else:
|
||||||
|
+ # Not a bootc transaction.
|
||||||
|
+ if self.conf.persistence == "transient":
|
||||||
|
+ raise CliError(_("Transient transactions are only supported on bootc systems."))
|
||||||
|
|
||||||
|
if self._promptWanted():
|
||||||
|
if self.conf.assumeno or not self.output.userconfirm():
|
||||||
|
raise CliError(_("Operation aborted."))
|
||||||
|
|
||||||
|
- if bootc:
|
||||||
|
- bootc.unlock_and_prepare()
|
||||||
|
+ if bootc_system:
|
||||||
|
+ bootc_system.make_writable()
|
||||||
|
else:
|
||||||
|
logger.info(_('Nothing to do.'))
|
||||||
|
return
|
||||||
|
diff --git a/dnf/util.py b/dnf/util.py
|
||||||
|
index 994fddafc..0161f80d8 100644
|
||||||
|
--- a/dnf/util.py
|
||||||
|
+++ b/dnf/util.py
|
||||||
|
@@ -25,6 +25,7 @@ from __future__ import unicode_literals
|
||||||
|
from .pycomp import PY3, basestring
|
||||||
|
from dnf.i18n import _, ucd
|
||||||
|
import argparse
|
||||||
|
+import ctypes
|
||||||
|
import dnf
|
||||||
|
import dnf.callback
|
||||||
|
import dnf.const
|
||||||
|
@@ -634,11 +635,12 @@ def _name_unset_wrapper(input_name):
|
||||||
|
return input_name if input_name else _("<name-unset>")
|
||||||
|
|
||||||
|
|
||||||
|
-class _Bootc:
|
||||||
|
+class _BootcSystem:
|
||||||
|
usr = "/usr"
|
||||||
|
+ CLONE_NEWNS = 0x00020000 # defined in linux/include/uapi/linux/sched.h
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
- if not self.is_bootc_host():
|
||||||
|
+ if not self.is_bootc_system():
|
||||||
|
raise RuntimeError(_("Not running on a bootc system."))
|
||||||
|
|
||||||
|
import gi
|
||||||
|
@@ -656,45 +658,87 @@ class _Bootc:
|
||||||
|
assert self._booted_deployment is not None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
- def is_bootc_host():
|
||||||
|
+ def is_bootc_system():
|
||||||
|
"""Returns true is the system is managed as an immutable container, false
|
||||||
|
otherwise."""
|
||||||
|
ostree_booted = "/run/ostree-booted"
|
||||||
|
return os.path.isfile(ostree_booted)
|
||||||
|
|
||||||
|
+ @classmethod
|
||||||
|
+ def is_writable(cls):
|
||||||
|
+ """Returns true if and only if /usr is writable."""
|
||||||
|
+ return os.access(cls.usr, os.W_OK)
|
||||||
|
+
|
||||||
|
def _get_unlocked_state(self):
|
||||||
|
return self._booted_deployment.get_unlocked()
|
||||||
|
|
||||||
|
- def is_unlocked(self):
|
||||||
|
- return self._get_unlocked_state() != self._OSTree.DeploymentUnlockedState.NONE
|
||||||
|
+ def is_unlocked_transient(self):
|
||||||
|
+ """Returns true if and only if the bootc system is unlocked in a
|
||||||
|
+ transient state, i.e. a overlayfs is mounted as read-only on /usr.
|
||||||
|
+ Changes can be made to the overlayfs by remounting /usr as
|
||||||
|
+ read/write in a private mount namespace."""
|
||||||
|
+ return self._get_unlocked_state() == self._OSTree.DeploymentUnlockedState.TRANSIENT
|
||||||
|
+
|
||||||
|
+ @classmethod
|
||||||
|
+ def _set_up_mountns(cls):
|
||||||
|
+ # os.unshare is only available in Python >= 3.12.
|
||||||
|
+
|
||||||
|
+ # Access symbols in libraries loaded by the Python interpreter,
|
||||||
|
+ # which will include libc. See https://bugs.python.org/issue34592.
|
||||||
|
+ libc = ctypes.CDLL(None)
|
||||||
|
+ if libc.unshare(cls.CLONE_NEWNS) != 0:
|
||||||
|
+ raise OSError("Failed to unshare mount namespace")
|
||||||
|
+
|
||||||
|
+ mount_command = ["mount", "--options-source=disable", "-o", "remount,rw", cls.usr]
|
||||||
|
+ try:
|
||||||
|
+ completed_process = subprocess.run(mount_command, text=True)
|
||||||
|
+ completed_process.check_returncode()
|
||||||
|
+ except FileNotFoundError:
|
||||||
|
+ raise dnf.exceptions.Error(_("%s: command not found.") % mount_command[0])
|
||||||
|
+ except subprocess.CalledProcessError:
|
||||||
|
+ raise dnf.exceptions.Error(_("Failed to mount %s as read/write: %s", cls.usr, completed_process.stderr))
|
||||||
|
|
||||||
|
- def unlock_and_prepare(self):
|
||||||
|
- """Set up a writeable overlay on bootc systems."""
|
||||||
|
+ @staticmethod
|
||||||
|
+ def _unlock():
|
||||||
|
+ unlock_command = ["ostree", "admin", "unlock", "--transient"]
|
||||||
|
+ try:
|
||||||
|
+ completed_process = subprocess.run(unlock_command, text=True)
|
||||||
|
+ completed_process.check_returncode()
|
||||||
|
+ except FileNotFoundError:
|
||||||
|
+ raise dnf.exceptions.Error(_("%s: command not found. Is this a bootc system?") % unlock_command[0])
|
||||||
|
+ except subprocess.CalledProcessError:
|
||||||
|
+ raise dnf.exceptions.Error(_("Failed to unlock system: %s", completed_process.stderr))
|
||||||
|
+
|
||||||
|
+ def make_writable(self):
|
||||||
|
+ """Set up a writable overlay on bootc systems."""
|
||||||
|
|
||||||
|
bootc_unlocked_state = self._get_unlocked_state()
|
||||||
|
|
||||||
|
valid_bootc_unlocked_states = (
|
||||||
|
self._OSTree.DeploymentUnlockedState.NONE,
|
||||||
|
self._OSTree.DeploymentUnlockedState.DEVELOPMENT,
|
||||||
|
- # self._OSTree.DeploymentUnlockedState.TRANSIENT,
|
||||||
|
- # self._OSTree.DeploymentUnlockedState.HOTFIX,
|
||||||
|
+ self._OSTree.DeploymentUnlockedState.TRANSIENT,
|
||||||
|
+ self._OSTree.DeploymentUnlockedState.HOTFIX,
|
||||||
|
)
|
||||||
|
-
|
||||||
|
if bootc_unlocked_state not in valid_bootc_unlocked_states:
|
||||||
|
raise ValueError(_("Unhandled bootc unlocked state: %s") % bootc_unlocked_state.value_nick)
|
||||||
|
|
||||||
|
- if bootc_unlocked_state == self._OSTree.DeploymentUnlockedState.DEVELOPMENT:
|
||||||
|
- # System is already unlocked.
|
||||||
|
+ writable_unlocked_states = (
|
||||||
|
+ self._OSTree.DeploymentUnlockedState.DEVELOPMENT,
|
||||||
|
+ self._OSTree.DeploymentUnlockedState.HOTFIX,
|
||||||
|
+ )
|
||||||
|
+ if bootc_unlocked_state in writable_unlocked_states:
|
||||||
|
+ # System is already unlocked in development mode, and usr is
|
||||||
|
+ # already mounted read/write.
|
||||||
|
pass
|
||||||
|
elif bootc_unlocked_state == self._OSTree.DeploymentUnlockedState.NONE:
|
||||||
|
- unlock_command = ["ostree", "admin", "unlock"]
|
||||||
|
-
|
||||||
|
- try:
|
||||||
|
- completed_process = subprocess.run(unlock_command, text=True)
|
||||||
|
- completed_process.check_returncode()
|
||||||
|
- except FileNotFoundError:
|
||||||
|
- raise dnf.exceptions.Error(_("ostree command not found. Is this a bootc system?"))
|
||||||
|
- except subprocess.CalledProcessError:
|
||||||
|
- raise dnf.exceptions.Error(_("Failed to unlock system: %s", completed_process.stderr))
|
||||||
|
+ # System is not unlocked. Unlock it in transient mode, then set up
|
||||||
|
+ # a mount namespace for DNF.
|
||||||
|
+ self._unlock()
|
||||||
|
+ self._set_up_mountns()
|
||||||
|
+ elif bootc_unlocked_state == self._OSTree.DeploymentUnlockedState.TRANSIENT:
|
||||||
|
+ # System is unlocked in transient mode, so usr is mounted
|
||||||
|
+ # read-only. Set up a mount namespace for DNF.
|
||||||
|
+ self._set_up_mountns()
|
||||||
|
|
||||||
|
assert os.access(self.usr, os.W_OK)
|
||||||
|
--
|
||||||
|
2.48.1
|
||||||
|
|
56
0043-spec-Add-dnf-bootc-subpackage.patch
Normal file
56
0043-spec-Add-dnf-bootc-subpackage.patch
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
From 9c2a1a6a36d748d059140bf6ee9113d5e9641477 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Evan Goode <mail@evangoo.de>
|
||||||
|
Date: Tue, 28 Jan 2025 11:27:00 -0500
|
||||||
|
Subject: [PATCH 43/44] spec: Add dnf-bootc subpackage
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Upstream commit: 76a0c339eb172b1b2a4b1aa8b4db8d6a5145916b
|
||||||
|
|
||||||
|
dnf-bootc's only job is to Require python3-gobject-base, ostree,
|
||||||
|
ostree-libs, and util-linux-core, which are needed to interact with
|
||||||
|
bootc systems. We don't want to add these dependencies on `python3-dnf`
|
||||||
|
because we don't want them on non-bootc systems, so we use a subpackage.
|
||||||
|
|
||||||
|
Resolves: https://issues.redhat.com/browse/RHEL-70917
|
||||||
|
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||||||
|
---
|
||||||
|
dnf.spec | 14 ++++++++++++++
|
||||||
|
1 file changed, 14 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/dnf.spec b/dnf.spec
|
||||||
|
index e9abd9041..b60f2692b 100644
|
||||||
|
--- a/dnf.spec
|
||||||
|
+++ b/dnf.spec
|
||||||
|
@@ -180,6 +180,17 @@ Requires: %{name} = %{version}-%{release}
|
||||||
|
%description automatic
|
||||||
|
Systemd units that can periodically download package upgrades and apply them.
|
||||||
|
|
||||||
|
+%package bootc
|
||||||
|
+Summary: %{pkg_summary} - additional bootc dependencies
|
||||||
|
+Requires: python3-%{name} = %{version}-%{release}
|
||||||
|
+Requires: ostree
|
||||||
|
+Requires: ostree-libs
|
||||||
|
+Requires: python3-gobject-base
|
||||||
|
+Requires: util-linux-core
|
||||||
|
+
|
||||||
|
+%description bootc
|
||||||
|
+Additional dependencies needed to perform transactions on booted bootc (bootable containers) systems.
|
||||||
|
+
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup
|
||||||
|
@@ -358,6 +369,9 @@ popd
|
||||||
|
%{_unitdir}/%{name}-automatic-install.timer
|
||||||
|
%{python3_sitelib}/%{name}/automatic/
|
||||||
|
|
||||||
|
+%files bootc
|
||||||
|
+# bootc subpackage does not include any files
|
||||||
|
+
|
||||||
|
%changelog
|
||||||
|
* Fri Sep 09 2022 Jaroslav Rohel <jrohel@redhat.com> - 4.14.0-1
|
||||||
|
- doc: Describe how gpg keys are stored for `repo_ggpcheck` (RhBug:2020678)
|
||||||
|
--
|
||||||
|
2.48.1
|
||||||
|
|
45
0044-Require-libdnf-0.74.0-with-persistence-option.patch
Normal file
45
0044-Require-libdnf-0.74.0-with-persistence-option.patch
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
From 19754a7c80e1c2232c370f394ad0d36f5713bf1e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Evan Goode <mail@evangoo.de>
|
||||||
|
Date: Wed, 5 Feb 2025 10:35:08 -0500
|
||||||
|
Subject: [PATCH 44/44] Require libdnf >= 0.74.0 with `persistence` option
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Upstream commit: 5a4f6c42e61ed764ff85eea69125947a280d665d
|
||||||
|
|
||||||
|
This backport actually uses RHEL-9 libdnf version.
|
||||||
|
|
||||||
|
Resolves: https://issues.redhat.com/browse/RHEL-70917
|
||||||
|
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||||||
|
---
|
||||||
|
dnf.spec | 6 +++++-
|
||||||
|
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/dnf.spec b/dnf.spec
|
||||||
|
index b60f2692b..313a3cb2a 100644
|
||||||
|
--- a/dnf.spec
|
||||||
|
+++ b/dnf.spec
|
||||||
|
@@ -2,7 +2,7 @@
|
||||||
|
%define __cmake_in_source_build 1
|
||||||
|
|
||||||
|
# default dependencies
|
||||||
|
-%global hawkey_version 0.66.0
|
||||||
|
+%global hawkey_version 0.74.0
|
||||||
|
%global libcomps_version 0.1.8
|
||||||
|
%global libmodulemd_version 2.9.3
|
||||||
|
%global rpm_version 4.14.0
|
||||||
|
@@ -21,6 +21,10 @@
|
||||||
|
%global rpm_version 4.11.3-25.el7.centos.1
|
||||||
|
%endif
|
||||||
|
|
||||||
|
+%if 0%{?rhel} == 9
|
||||||
|
+ %global hawkey_version 0.69.0-13
|
||||||
|
+%endif
|
||||||
|
+
|
||||||
|
# override dependencies for fedora 26
|
||||||
|
%if 0%{?fedora} == 26
|
||||||
|
%global rpm_version 4.13.0.1-7
|
||||||
|
--
|
||||||
|
2.48.1
|
||||||
|
|
31
dnf.spec
31
dnf.spec
@ -2,7 +2,7 @@
|
|||||||
%define __cmake_in_source_build 1
|
%define __cmake_in_source_build 1
|
||||||
|
|
||||||
# default dependencies
|
# default dependencies
|
||||||
%global hawkey_version 0.66.0
|
%global hawkey_version 0.74.0
|
||||||
%global libcomps_version 0.1.8
|
%global libcomps_version 0.1.8
|
||||||
%global libmodulemd_version 2.9.3
|
%global libmodulemd_version 2.9.3
|
||||||
%global rpm_version 4.14.0
|
%global rpm_version 4.14.0
|
||||||
@ -21,6 +21,10 @@
|
|||||||
%global rpm_version 4.11.3-25.el7.centos.1
|
%global rpm_version 4.11.3-25.el7.centos.1
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
%if 0%{?rhel} == 9
|
||||||
|
%global hawkey_version 0.69.0-13
|
||||||
|
%endif
|
||||||
|
|
||||||
# override dependencies for fedora 26
|
# override dependencies for fedora 26
|
||||||
%if 0%{?fedora} == 26
|
%if 0%{?fedora} == 26
|
||||||
%global rpm_version 4.13.0.1-7
|
%global rpm_version 4.13.0.1-7
|
||||||
@ -69,7 +73,7 @@ It supports RPMs, modules and comps groups & environments.
|
|||||||
|
|
||||||
Name: dnf
|
Name: dnf
|
||||||
Version: 4.14.0
|
Version: 4.14.0
|
||||||
Release: 24%{?dist}
|
Release: 25%{?dist}
|
||||||
Summary: %{pkg_summary}
|
Summary: %{pkg_summary}
|
||||||
# For a breakdown of the licensing, see PACKAGE-LICENSING
|
# For a breakdown of the licensing, see PACKAGE-LICENSING
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
@ -113,6 +117,12 @@ Patch35: 0035-automatic-Enhance-errors-reporting.patch
|
|||||||
Patch36: 0036-Update-need_reboot-for-dnf-automatic.patch
|
Patch36: 0036-Update-need_reboot-for-dnf-automatic.patch
|
||||||
Patch37: 0037-automatic-Fix-incorrect-Error-class-instantiation.patch
|
Patch37: 0037-automatic-Fix-incorrect-Error-class-instantiation.patch
|
||||||
PAtch38: 0038-doc-disableexcludepkgs-all-doesn-t-affect-just-file.patch
|
PAtch38: 0038-doc-disableexcludepkgs-all-doesn-t-affect-just-file.patch
|
||||||
|
Patch39: 0039-Add-support-for-transient.patch
|
||||||
|
Patch40: 0040-bootc-Document-transient-and-persistence.patch
|
||||||
|
Patch41: 0041-bootc-Use-ostree-GObject-API-to-get-deployment-statu.patch
|
||||||
|
Patch42: 0042-bootc-Re-locking-use-ostree-admin-unlock-transient.patch
|
||||||
|
Patch43: 0043-spec-Add-dnf-bootc-subpackage.patch
|
||||||
|
Patch44: 0044-Require-libdnf-0.74.0-with-persistence-option.patch
|
||||||
|
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
BuildRequires: cmake
|
BuildRequires: cmake
|
||||||
@ -222,6 +232,17 @@ Requires: %{name} = %{version}-%{release}
|
|||||||
%description automatic
|
%description automatic
|
||||||
Systemd units that can periodically download package upgrades and apply them.
|
Systemd units that can periodically download package upgrades and apply them.
|
||||||
|
|
||||||
|
%package bootc
|
||||||
|
Summary: %{pkg_summary} - additional bootc dependencies
|
||||||
|
Requires: python3-%{name} = %{version}-%{release}
|
||||||
|
Requires: ostree
|
||||||
|
Requires: ostree-libs
|
||||||
|
Requires: python3-gobject-base
|
||||||
|
Requires: util-linux-core
|
||||||
|
|
||||||
|
%description bootc
|
||||||
|
Additional dependencies needed to perform transactions on booted bootc (bootable containers) systems.
|
||||||
|
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%autosetup -p1
|
%autosetup -p1
|
||||||
@ -400,7 +421,13 @@ popd
|
|||||||
%{_unitdir}/%{name}-automatic-install.timer
|
%{_unitdir}/%{name}-automatic-install.timer
|
||||||
%{python3_sitelib}/%{name}/automatic/
|
%{python3_sitelib}/%{name}/automatic/
|
||||||
|
|
||||||
|
%files bootc
|
||||||
|
# bootc subpackage does not include any files
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Feb 04 2025 Petr Pisar <ppisar@redhat.com> - 4.14.0-25
|
||||||
|
- Add support for transient transactions (RHEL-70917)
|
||||||
|
|
||||||
* Mon Jan 13 2025 Ales Matej <amatej@redhat.com> - 4.14.0-24
|
* Mon Jan 13 2025 Ales Matej <amatej@redhat.com> - 4.14.0-24
|
||||||
- doc: `--disableexcludepkgs=all` doesn't affect just file configuration
|
- doc: `--disableexcludepkgs=all` doesn't affect just file configuration
|
||||||
(RHEL-28779)
|
(RHEL-28779)
|
||||||
|
Loading…
Reference in New Issue
Block a user