Skip to content

Commit

Permalink
Enable RPM OSTree from container source in payload (#2125655)
Browse files Browse the repository at this point in the history
We have a new RPMOStreeContainer source now which enables us to use
containers as installation source. In this commit we adapt the current
rpm_ostree to be able to consume this new container source.

Add a lot of rpm ostree tasks tests for the container source.

Resolves: RHEL-2250
  • Loading branch information
rvykydal committed Jan 12, 2024
1 parent 0d93341 commit 3ad22b2
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 30 deletions.
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
109 changes: 94 additions & 15 deletions pyanaconda/modules/payloads/payload/rpm_ostree/installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,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)


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


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


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

Expand Down Expand Up @@ -119,7 +173,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._source_config.osname + '/var'
# osname was used for ostreesetup but ostreecontainer renamed it to stateroot
stateroot = _get_stateroot(self._source_config)

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 @@ -325,7 +382,7 @@ def run(self):

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 All @@ -336,9 +393,12 @@ def run(self):
else:
root = None

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

repo.remote_change(root,
OSTree.RepoRemoteChange.ADD_IF_NOT_EXISTS,
self._data.remote,
remote,
self._data.url,
Variant('a{sv}', remote_options),
cancellable)
Expand Down Expand Up @@ -413,7 +473,8 @@ def name(self):

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 @@ -422,21 +483,39 @@ def run(self):
["admin",
"--sysroot=" + self._sysroot,
"os-init",
self._data.osname]
stateroot]
)

log.info("ostree admin deploy starting")
if self._data.is_container():
log.info("ostree image deploy starting")

safe_exec_with_redirect(
"ostree",
["admin",
"--sysroot=" + self._sysroot,
"deploy",
"--os=" + self._data.osname,
self._data.remote + ':' + ref]
)
args = ["container", "image", "deploy",
"--sysroot=" + self._sysroot,
"--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")

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

log.info("ostree admin deploy complete")
log.info("ostree deploy complete")
self.report_progress(_("Deployment complete: {}").format(ref))


Expand Down
3 changes: 2 additions & 1 deletion pyanaconda/modules/payloads/payload/rpm_ostree/rpm_ostree.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def type(self):
def supported_source_types(self):
"""Get list of sources supported by the RPM OSTree module."""
return [
SourceType.RPM_OSTREE
SourceType.RPM_OSTREE,
SourceType.RPM_OSTREE_CONTAINER,
]

def process_kickstart(self, data):
Expand Down
2 changes: 2 additions & 0 deletions pyanaconda/modules/payloads/source/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ def get_rpm_ostree_type_for_kickstart(ks_data):
:param ks_data: kickstart data from DNF payload
:return: SourceType value
"""
if ks_data.ostreecontainer.seen:
return SourceType.RPM_OSTREE_CONTAINER
if ks_data.ostreesetup.seen:
return SourceType.RPM_OSTREE

Expand Down
30 changes: 19 additions & 11 deletions pyanaconda/payload/rpmostreepayload.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@

from subprocess import CalledProcessError

from pyanaconda.core.constants import PAYLOAD_TYPE_RPM_OSTREE, SOURCE_TYPE_RPM_OSTREE
from pyanaconda.modules.common.structures.rpm_ostree import RPMOSTreeConfigurationData
from pyanaconda.core.constants import PAYLOAD_TYPE_RPM_OSTREE, SOURCE_TYPE_RPM_OSTREE, \
SOURCE_TYPE_RPM_OSTREE_CONTAINER
from pyanaconda.modules.common.structures.rpm_ostree import RPMOSTreeConfigurationData, \
RPMOSTreeContainerConfigurationData
from pyanaconda.progress import progressQ
from pyanaconda.payload.base import Payload
from pyanaconda.payload import utils as payload_utils
Expand Down Expand Up @@ -62,13 +64,18 @@ def source_type(self):
def _get_source_configuration(self):
"""Get the configuration of the RPM OSTree source.
:return: an instance of RPMOSTreeConfigurationData
:return: an instance of RPMOSTreeConfigurationData or RPMOSTreeContainerConfigurationData
"""
source_proxy = self.get_source_proxy()

return RPMOSTreeConfigurationData.from_structure(
source_proxy.Configuration
)
if self.source_type == SOURCE_TYPE_RPM_OSTREE_CONTAINER:
return RPMOSTreeContainerConfigurationData.from_structure(
source_proxy.Configuration
)
else:
return RPMOSTreeConfigurationData.from_structure(
source_proxy.Configuration
)

@property
def kernel_version_list(self):
Expand Down Expand Up @@ -124,11 +131,12 @@ def _install(self, data):
)
task.run()

from pyanaconda.modules.payloads.payload.rpm_ostree.installation import \
PullRemoteAndDeleteTask
task = PullRemoteAndDeleteTask(data)
task.progress_changed_signal.connect(self._progress_cb)
task.run()
if not data.is_container():
from pyanaconda.modules.payloads.payload.rpm_ostree.installation import \
PullRemoteAndDeleteTask
task = PullRemoteAndDeleteTask(data)
task.progress_changed_signal.connect(self._progress_cb)
task.run()

from pyanaconda.modules.payloads.payload.rpm_ostree.installation import DeployOSTreeTask
task = DeployOSTreeTask(data, conf.target.physical_root)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#
import unittest

from pyanaconda.core.constants import SOURCE_TYPE_RPM_OSTREE
from pyanaconda.core.constants import SOURCE_TYPE_RPM_OSTREE, SOURCE_TYPE_RPM_OSTREE_CONTAINER
from pyanaconda.modules.payloads.constants import PayloadType
from pyanaconda.modules.payloads.payload.rpm_ostree.rpm_ostree import RPMOSTreeModule
from pyanaconda.modules.payloads.payload.rpm_ostree.rpm_ostree_interface import RPMOSTreeInterface
Expand Down Expand Up @@ -47,7 +47,8 @@ def test_type(self):
def test_supported_sources(self):
"""Test the SupportedSourceTypes property."""
assert self.interface.SupportedSourceTypes == [
SOURCE_TYPE_RPM_OSTREE
SOURCE_TYPE_RPM_OSTREE,
SOURCE_TYPE_RPM_OSTREE_CONTAINER,
]


Expand Down

0 comments on commit 3ad22b2

Please sign in to comment.