Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Master enable ostree containers #4561

Merged
Merged
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
6 changes: 6 additions & 0 deletions anaconda.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Source0: https://github.com/rhinstaller/%{name}/releases/download/%{name}-%{vers
%define simplelinever 1.9.0-1
%define subscriptionmanagerver 1.26
%define utillinuxver 2.15.1
%define rpmostreever 2023.2

BuildRequires: libtool
BuildRequires: gettext-devel >= %{gettextver}
Expand Down Expand Up @@ -102,6 +103,11 @@ Requires: python3-systemd
Requires: python3-productmd
Requires: python3-dasbus >= %{dasbusver}
Requires: flatpak-libs
# dependencies for rpm-ostree payload module
Requires: rpm-ostree >= %{rpmostreever}
Requires: ostree
# used by ostree command for native containers
Requires: skopeo
%if %{defined rhel} && %{undefined centos}
Requires: subscription-manager >= %{subscriptionmanagerver}
%endif
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ AC_CONFIG_FILES([Makefile
pyanaconda/modules/payloads/source/repo_files/Makefile
pyanaconda/modules/payloads/source/repo_path/Makefile
pyanaconda/modules/payloads/source/rpm_ostree/Makefile
pyanaconda/modules/payloads/source/rpm_ostree_container/Makefile
pyanaconda/modules/payloads/source/url/Makefile
pyanaconda/modules/storage/Makefile
pyanaconda/modules/storage/bootloader/Makefile
Expand Down
14 changes: 14 additions & 0 deletions docs/release-notes/ostree-native-containers-support.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
:Type: Kickstart
:Summary: Add support for OSTree native containers (#2125655)

:Description:
Fedora is adding a new enhanced container support for the (rpm-)ostree stack to
natively support OCI/Docker containers as a transport and delivery mechanism
for operating system content. Anaconda now supports these containers by
a new kickstart command `ostreecontainer`.

:Links:
- https://bugzilla.redhat.com/show_bug.cgi?id=2125655
- https://fedoraproject.org/wiki/Changes/OstreeNativeContainer
- https://fedoraproject.org/wiki/Changes/OstreeNativeContainerStable
- https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html#ostreecontainer
1 change: 1 addition & 0 deletions pyanaconda/core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ class DisplayModes(Enum):
SOURCE_TYPE_LIVE_IMAGE = "LIVE_IMAGE"
SOURCE_TYPE_LIVE_TAR = "LIVE_TAR"
SOURCE_TYPE_RPM_OSTREE = "RPM_OSTREE"
SOURCE_TYPE_RPM_OSTREE_CONTAINER = "RPM_OSTREE_CONTAINER"
SOURCE_TYPE_FLATPAK = "FLATPAK"
SOURCE_TYPE_HMC = "HMC"
SOURCE_TYPE_CDROM = "CDROM"
Expand Down
3 changes: 2 additions & 1 deletion pyanaconda/core/kickstart/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
from pykickstart.commands.network import F39_Network as Network
from pykickstart.commands.nfs import FC6_NFS as NFS
from pykickstart.commands.nvdimm import F28_Nvdimm as Nvdimm
from pykickstart.commands.ostreesetup import F21_OSTreeSetup as OSTreeSetup
from pykickstart.commands.ostreecontainer import F38_OSTreeContainer as OSTreeContainer
from pykickstart.commands.ostreesetup import F38_OSTreeSetup as OSTreeSetup
from pykickstart.commands.partition import F34_Partition as Partition
from pykickstart.commands.raid import F29_Raid as Raid
from pykickstart.commands.realm import F19_Realm as Realm
Expand Down
5 changes: 5 additions & 0 deletions pyanaconda/modules/common/constants/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@
basename="RPMOSTree"
)

PAYLOAD_SOURCE_RPM_OSTREE_CONTAINER = DBusInterfaceIdentifier(
namespace=SOURCE_NAMESPACE,
basename="RPMOSTreeContainer"
)

PAYLOAD_SOURCE_FLATPAK = DBusInterfaceIdentifier(
namespace=SOURCE_NAMESPACE,
basename="Flatpak"
Expand Down
74 changes: 73 additions & 1 deletion pyanaconda/modules/common/structures/rpm_ostree.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from dasbus.structure import DBusData
from dasbus.typing import Str, Bool

__all__ = ["RPMOSTreeConfigurationData"]
__all__ = ["RPMOSTreeConfigurationData", "RPMOSTreeContainerConfigurationData"]


class RPMOSTreeConfigurationData(DBusData):
Expand All @@ -33,6 +33,11 @@ def __init__(self):
self._ref = ""
self._gpg_verification_enabled = True

@staticmethod
def is_container():
"""Is this native container source?"""
return False
Comment on lines +36 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You extended this class so it's the same as the new class... but then made it different anyway?


@property
def osname(self) -> Str:
"""Management root for OS installation."""
Expand Down Expand Up @@ -77,3 +82,70 @@ def gpg_verification_enabled(self) -> Bool:
@gpg_verification_enabled.setter
def gpg_verification_enabled(self, value: Bool):
self._gpg_verification_enabled = value


class RPMOSTreeContainerConfigurationData(DBusData):
"""Structure to hold RPM OSTree from container configuration."""

def __init__(self):
self._stateroot = ""
self._remote = ""
self._transport = ""
self._url = ""
self._signature_verification_enabled = True

@staticmethod
def is_container():
"""Is this native container source?"""
return True

@property
def stateroot(self) -> Str:
"""Name for the state directory, also known as "osname".

This could be optional.
"""
return self._stateroot

@stateroot.setter
def stateroot(self, value: Str):
self._stateroot = value

@property
def transport(self) -> Str:
"""Ostree transport protocol used.

This could be optional (default will be 'repository').
"""
return self._transport

@transport.setter
def transport(self, value: Str):
self._transport = value

@property
def remote(self) -> Str:
"""Name of the OSTree remote."""
return self._remote

@remote.setter
def remote(self, value: Str):
self._remote = value

@property
def url(self) -> Str:
"""URL of the repository to install from."""
return self._url

@url.setter
def url(self, value: Str):
self._url = value

@property
def signature_verification_enabled(self) -> Bool:
poncovka marked this conversation as resolved.
Show resolved Hide resolved
"""Is the GPG key verification enabled?"""
return self._signature_verification_enabled

@signature_verification_enabled.setter
def signature_verification_enabled(self, value: Bool):
self._signature_verification_enabled = value
4 changes: 3 additions & 1 deletion pyanaconda/modules/payloads/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
PAYLOAD_TYPE_DNF, PAYLOAD_TYPE_LIVE_OS, PAYLOAD_TYPE_LIVE_IMAGE, \
SOURCE_TYPE_LIVE_OS_IMAGE, SOURCE_TYPE_HMC, SOURCE_TYPE_CDROM, SOURCE_TYPE_REPO_FILES, \
SOURCE_TYPE_REPO_PATH, SOURCE_TYPE_NFS, SOURCE_TYPE_URL, SOURCE_TYPE_HDD, SOURCE_TYPE_CDN, \
SOURCE_TYPE_CLOSEST_MIRROR, PAYLOAD_TYPE_RPM_OSTREE, SOURCE_TYPE_RPM_OSTREE, \
SOURCE_TYPE_CLOSEST_MIRROR, PAYLOAD_TYPE_RPM_OSTREE, \
SOURCE_TYPE_RPM_OSTREE, SOURCE_TYPE_RPM_OSTREE_CONTAINER, \
SOURCE_TYPE_LIVE_IMAGE, SOURCE_TYPE_FLATPAK, SOURCE_TYPE_LIVE_TAR

# Locations of repo files.
Expand All @@ -48,6 +49,7 @@ class SourceType(Enum):
LIVE_IMAGE = SOURCE_TYPE_LIVE_IMAGE
LIVE_TAR = SOURCE_TYPE_LIVE_TAR
RPM_OSTREE = SOURCE_TYPE_RPM_OSTREE
RPM_OSTREE_CONTAINER = SOURCE_TYPE_RPM_OSTREE_CONTAINER
FLATPAK = SOURCE_TYPE_FLATPAK
HMC = SOURCE_TYPE_HMC
CDROM = SOURCE_TYPE_CDROM
Expand Down
1 change: 1 addition & 0 deletions pyanaconda/modules/payloads/kickstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ class PayloadKickstartSpecification(KickstartSpecification):
"liveimg": COMMANDS.Liveimg,
"module": COMMANDS.Module,
"nfs": COMMANDS.NFS,
"ostreecontainer": COMMANDS.OSTreeContainer,
"ostreesetup": COMMANDS.OSTreeSetup,
"repo": COMMANDS.Repo,
"url": COMMANDS.Url
Expand Down
2 changes: 1 addition & 1 deletion pyanaconda/modules/payloads/payload/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def get_type_for_kickstart(cls, data):
:param data: a kickstart data
:return: a payload type
"""
if data.ostreesetup.seen:
if data.ostreesetup.seen or data.ostreecontainer.seen:
return PayloadType.RPM_OSTREE

if data.liveimg.seen:
Expand Down
110 changes: 94 additions & 16 deletions pyanaconda/modules/payloads/payload/rpm_ostree/installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,60 @@ def safe_exec_with_redirect(cmd, argv, successful_return_codes=(0,), **kwargs):
)


def _get_ref(data):
"""Get ref or name based on source.

OSTree container don't have ref because it's specified by the container. In that case let's
return just url for reporting.

:param data: OSTree source structure
:return str: ref or name based on source
"""
# Variable substitute the ref: https://pagure.io/atomic-wg/issue/299
if data.is_container():
# we don't have ref with container; there are not multiple references in one container
return data.url
else:
return RpmOstree.varsubst_basearch(data.ref)
Comment on lines +66 to +71
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is above both calls, so perhaps you should substitute also for the url?



def _get_stateroot(data):
"""Get stateroot.

The OSTree renamed old osname to stateroot for containers.

:param data: OSTree source structure
:return str: stateroot or osname value based on source
"""
if data.is_container():
# osname was renamed to stateroot so let's use the new name
if data.stateroot:
return data.stateroot
else:
# The stateroot doesn't have to be defined
# https://github.com/ostreedev/ostree-rs-ext/pull/462/files
# However, it's working just for a subset of calls now.
# TODO: Remove this when all ostree commands undestarstands this
return "default"
else:
return data.osname
Comment on lines +74 to +93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this code simply does not have to exist. I think you should have renamed one of these fields so that they match. Especially when the first thing "stateroot" docstring says is that it's the osname...



def _get_verification_enabled(data):
"""Find out if source has enabled verification.

OSTree sources has different names for enabled verification. This helper function
will make the access consistent.

:param data: OSTree source structure
:return bool: True if verification is enabled
"""
if data.is_container():
return data.signature_verification_enabled
else:
return data.gpg_verification_enabled
Comment on lines +105 to +108
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here. If it's the same thing, just call it the same. The docstrings also say that it's just gpg now, so why did we have to invent a new name?



class PrepareOSTreeMountTargetsTask(Task):
"""Task to prepare OSTree mount targets."""

Expand Down Expand Up @@ -132,7 +186,10 @@ def _handle_var_mount_point(self, existing_mount_points):

:param [] existing_mount_points: a list of existing mount points
"""
var_root = '/ostree/deploy/' + self._data.osname + '/var'
# osname was used for ostreesetup but ostreecontainer renamed it to stateroot
stateroot = _get_stateroot(self._data)

var_root = '/ostree/deploy/' + stateroot + '/var'
if existing_mount_points.get("/var") is None:
self._setup_internal_bindmount(var_root, dest='/var', recurse=False)
else:
Expand Down Expand Up @@ -397,11 +454,14 @@ def run(self):
# We don't support resuming from interrupted installs.
repo.set_disable_fsync(True)

# Remote is set or it should be named as stateroot is
remote = self._data.remote or _get_stateroot(self._data)

# Add a remote if it doesn't exist.
repo.remote_change(
sysroot_file if self._sysroot else None,
OSTree.RepoRemoteChange.ADD_IF_NOT_EXISTS,
self._data.remote,
remote,
self._data.url,
self._get_remote_options(),
cancellable=None
Expand All @@ -411,7 +471,7 @@ def _get_remote_options(self):
"""Get the remote options."""
remote_options = {}

if not self._data.gpg_verification_enabled:
if not _get_verification_enabled(self._data):
remote_options['gpg-verify'] = Variant('b', False)

if not conf.payload.verify_ssl:
Expand Down Expand Up @@ -486,8 +546,8 @@ class DeployOSTreeTask(Task):
def __init__(self, data, physroot):
"""Create a new task.

:param str physroot: a path to the physical root
:param data: an RPM OSTree configuration
:param str physroot: a path to the physical root
"""
super().__init__()
self._data = data
Expand All @@ -498,8 +558,8 @@ def name(self):
return "Deploy OSTree"

def run(self):
# Variable substitute the ref: https://pagure.io/atomic-wg/issue/299
ref = RpmOstree.varsubst_basearch(self._data.ref)
ref = _get_ref(self._data)
stateroot = _get_stateroot(self._data)

self.report_progress(_("Deployment starting: {}").format(ref))

Expand All @@ -508,19 +568,37 @@ def run(self):
["admin",
"--sysroot=" + self._physroot,
"os-init",
self._data.osname]
stateroot]
)

log.info("ostree admin deploy starting")
if self._data.is_container():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part and below feel as if you forgot that polymorphism exists?

log.info("ostree image deploy starting")

safe_exec_with_redirect(
"ostree",
["admin",
"--sysroot=" + self._physroot,
"deploy",
"--os=" + self._data.osname,
self._data.remote + ':' + ref]
)
args = ["container", "image", "deploy",
"--sysroot=" + self._physroot,
"--image=" + ref]

if self._data.transport:
args.append("--transport=" + self._data.transport)
if self._data.stateroot:
args.append("--stateroot=" + self._data.stateroot)
if not self._data.signature_verification_enabled:
args.append("--no-signature-verification")
VladimirSlavik marked this conversation as resolved.
Show resolved Hide resolved

safe_exec_with_redirect(
"ostree",
args
)
else:
log.info("ostree admin deploy starting")
safe_exec_with_redirect(
"ostree",
["admin",
"--sysroot=" + self._physroot,
"deploy",
"--os=" + stateroot,
self._data.remote + ':' + ref]
)

log.info("ostree config set sysroot.readonly true")

Expand Down
Loading