Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .github/workflows/build_and_test_qnx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ jobs:
- name: Run integration tests
run: |
bazel test --lockfile_mode=error --config=itf-qnx-x86_64 //feature_integration_tests/itf
- name: Run platform integration tests
run: |
bazel test --lockfile_mode=error --config=itf-qnx-x86_64 //platform_integration_tests:pit
- name: Cleanup QNX license
if: always()
run: sudo rm -rf /opt/score_qnx
43 changes: 43 additions & 0 deletions deploy/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup")
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")

exports_files(["README.md"])

# The S-CORE platform as deployed by this distribution: every binary and
# configuration file that an S-CORE module contributes to the shipped image.
# This is the system under test for the conformance showcases; it must stay
# free of anything that only exists to demonstrate or test the platform.
#
# Consumed by the QNX images via qnx_ifs srcs.
pkg_filegroup(
name = "platform_bundle",
srcs = [
"//deploy/communication:etc_comm_configs",
"//deploy/config_management:config_daemon_bin",
"//deploy/config_management:config_daemon_configs",
"//deploy/lifecycle:launch_manager_bin",
"//deploy/logging:datarouter_bin",
"//deploy/logging:datarouter_configs",
],
visibility = ["//visibility:public"],
)

# Same content as :platform_bundle, as a tar for oci_image consumers.
pkg_tar(
name = "platform_tar",
srcs = [":platform_bundle"],
visibility = ["//visibility:public"],
)
58 changes: 58 additions & 0 deletions deploy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Platform deployment (layer 2)

The image content of this distribution is split into three layers:

| Layer | Location | Content |
| --- | --- | --- |
| 1 — Image | `//images/<variant>` | Boot, kernel, drivers, root filesystem skeleton |
| 2 — Platform | `//deploy` | The S-CORE modules as deployed — the system under test |
| 3 — Showcases | `//showcases` | Applications that demonstrate and verify the platform |

A production image ships layers 1 and 2. Layer 3 must be removable without
changing either of them.

## Why layer 2 and layer 3 are separate

The showcases are the probe, the platform is the probe's subject. If a
showcase shipped the component it exercises — as the lifecycle showcase did
with the launch manager before this split — then the check would be verifying
the binary it brought along rather than the one the distribution deployed. A
distribution that fails to deploy an S-CORE module would still pass.

Keeping them apart gives the property that makes the checks meaningful: the
showcase applications run against whatever platform the image provides, and
fail when it is missing.

That is also why a module's binaries can end up in different layers. The
lifecycle launch manager is deployed here; the applications it supervises,
and the launch manager configuration that declares them, live in
`//showcases/simple_lifecycle`.

## Contract between layer 2 and layer 3

Layer 3 may rely on the following, and on nothing else:

| Component | Deployed location |
| --- | --- |
| `launch_manager` | `/usr/bin/launch_manager` |
| `datarouter` | `/usr/bin/datarouter/datarouter`, config in `/usr/bin/datarouter/etc` |
| `config_daemon` | `/usr/bin/config_management/config_daemon`, config in `/usr/bin/config_management/etc` |
| mw::com system configuration | `/etc/mw_com_config.json` |

Layer 2 never references anything under `/showcases`. The one place where
layer 2 reads layer 3 data is the launch manager, which is started by the
showcase with a working directory that holds the showcase's own
configuration — the configuration is passed in, not deployed alongside the
daemon.

## Adding a module

Add a `deploy/<module>/BUILD` that packages the module's binaries and
configuration with `pkg_files`, then list those targets in
`//deploy:platform_bundle`. Configuration that is deployed onto the target
is kept in `deploy/<module>/etc/`, not in a test directory. Keep examples,
demo applications and test binaries out; those belong in `//showcases`.

Long term each S-CORE module should export its own deployment package
upstream, so that "deployed correctly" becomes checkable rather than agreed.
Until then this directory is the distribution's local stand-in for it.
43 changes: 43 additions & 0 deletions deploy/communication/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

# Deployment of the S-CORE communication module (layer 2, see //deploy:README.md).
#
# Communication ships as a library, so the only deployed artifacts are the
# system-wide configuration files every mw::com participant reads from /etc.

load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files", "strip_prefix")

package(default_visibility = ["//deploy:__pkg__"])

pkg_files(
name = "etc_comm_configs",
srcs = [
"etc/logging.json",
"etc/mw_com_config.json",
],
attributes = pkg_attributes(mode = "0777"),
prefix = "etc",
strip_prefix = strip_prefix.files_only(),
)

# Same files as a plain filegroup, for images that assemble /etc themselves
# instead of consuming rules_pkg providers.
filegroup(
name = "etc_configs",
srcs = [
"etc/logging.json",
"etc/mw_com_config.json",
],
visibility = ["//visibility:public"],
)
45 changes: 45 additions & 0 deletions deploy/config_management/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

# Deployment of the S-CORE config management module (layer 2, see //deploy:README.md).

load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files", "strip_prefix")

package(default_visibility = ["//deploy:__pkg__"])

# Config daemon binary (0777), placed as /usr/bin/config_management/config_daemon.
pkg_files(
name = "config_daemon_bin",
srcs = ["@score_config_management//score/config_management/config_daemon/code:config_daemon"],
attributes = pkg_attributes(mode = "0777"),
prefix = "usr/bin/config_management",
strip_prefix = strip_prefix.files_only(),
)

# Config daemon configuration (0644), placed under
# /usr/bin/config_management/etc. Both files are shipped by the upstream
# module, so they belong to the deployment and not to the showcase that
# drives the daemon.
pkg_files(
name = "config_daemon_configs",
srcs = [
"@score_config_management//score/config_management/config_daemon/code/plugins/demo_json:demo_parameters",
"@score_config_management//score/config_management/config_daemon/code/services/details/mw_com:mw_com_config",
],
attributes = pkg_attributes(mode = "0644"),
prefix = "usr/bin/config_management/etc",
renames = {
"@score_config_management//score/config_management/config_daemon/code/services/details/mw_com:mw_com_config": "mw_com_config.json",
"@score_config_management//score/config_management/config_daemon/code/plugins/demo_json:demo_parameters": "demo_parameters.json",
},
)
32 changes: 32 additions & 0 deletions deploy/lifecycle/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

# Deployment of the S-CORE lifecycle module (layer 2, see //deploy:README.md).
#
# Only the launch manager daemon is deployed here. The applications it
# supervises, and the launch manager configuration that declares them, are
# payload of whoever uses the platform - for this repository that is the
# lifecycle showcase in //showcases/simple_lifecycle.

load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files", "strip_prefix")

package(default_visibility = ["//deploy:__pkg__"])

# Launch manager binary (0777), placed as /usr/bin/launch_manager.
pkg_files(
name = "launch_manager_bin",
srcs = ["@score_lifecycle//score/launch_manager"],
attributes = pkg_attributes(mode = "0777"),
prefix = "usr/bin",
strip_prefix = strip_prefix.files_only(),
)
39 changes: 39 additions & 0 deletions deploy/logging/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

# Deployment of the S-CORE logging module (layer 2, see //deploy:README.md).

load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files", "strip_prefix")

package(default_visibility = ["//deploy:__pkg__"])

# Datarouter binary (0777), placed under /usr/bin/datarouter.
pkg_files(
name = "datarouter_bin",
srcs = ["@score_logging//score/datarouter"],
attributes = pkg_attributes(mode = "0777"),
prefix = "usr/bin/datarouter",
strip_prefix = strip_prefix.files_only(),
)

# Datarouter configuration files (0644), placed under /usr/bin/datarouter/etc.
pkg_files(
name = "datarouter_configs",
srcs = [
"etc/log-channels.json",
"etc/logging.json",
],
attributes = pkg_attributes(mode = "0644"),
prefix = "usr/bin/datarouter/etc",
strip_prefix = strip_prefix.files_only(),
)
69 changes: 46 additions & 23 deletions docs/integration_process/step_4_platforms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,39 +176,64 @@ job** automatically.

.. _add_directly:

Add a binary directly to an image
---------------------------------

If your component is not a CLI showcase — for example a background daemon that
must always be present — you wire it straight into each image's build
description instead. Unlike the showcase route, **this is per-image work: you
repeat it for every image you target** (Linux, QNX, AutoSD, EBcLfSA).

The reference example is the ``datarouter``. Its destination path, permissions
and owner are declared once as a ``pkg_files`` target; because the binary is
resolved per platform (not per architecture) the definition is shared from
``images/common/apps`` and each image lists it in its ``srcs``.
``score_rules_imagefs`` then generates the matching ``mkifs`` directives, so
nothing has to be added to ``system.build``:
Deploy a component as part of the platform
------------------------------------------

If your component is not a showcase — for example a background daemon that must
always be present — it belongs to the *deployed platform* rather than to the
demonstration layer. The image content is split into three layers:

* **Image** (``images/<variant>``) — boot, kernel, drivers, rootfs skeleton.
* **Platform** (``deploy/``) — the S-CORE modules as deployed. This is what a
conformance check treats as the system under test.
* **Showcases** (``showcases/``) — applications that demonstrate and verify the
platform, removable without touching the two layers below.

Keep the two apart: a showcase must never ship the component it exercises,
otherwise it verifies the binary it brought along instead of the one the
distribution deployed. The lifecycle module is the illustrative case — the
``launch_manager`` daemon is deployed from ``deploy/lifecycle``, while the
applications it supervises stay in ``showcases/simple_lifecycle``.

**1. Package the component.** Declare destination path and permissions as a
``pkg_files`` target in ``deploy/<module>/BUILD``. Because the binary is
resolved per platform (not per architecture), one definition serves every
image, and ``score_rules_imagefs`` generates the matching ``mkifs`` directives
so nothing has to be added to ``system.build``:

.. code-block:: python

# images/common/apps/BUILD (defined once, shared by every image)
# deploy/logging/BUILD
pkg_files(
name = "datarouter_bin",
srcs = ["@score_logging//score/datarouter"],
attributes = pkg_attributes(mode = "0777"),
prefix = "usr/bin/datarouter",
strip_prefix = strip_prefix.files_only(),
)

**2. Register it in the platform bundle.** Unlike the showcase route this is
*not* per-image work: every image already consumes the aggregate, so adding
your target to it is enough.

.. code-block:: python

# deploy/BUILD
pkg_filegroup(
name = "platform_bundle",
srcs = [
# ...
"//deploy/logging:datarouter_bin",
],
visibility = ["//visibility:public"],
)

# images/qnx_x86_64/build/BUILD (referenced per image)
# images/qnx_x86_64/build/BUILD (already present, shown for context)
qnx_ifs(
name = "init",
srcs = [
# ...
"//images/common/apps:datarouter_bin",
"//deploy:platform_bundle",
],
build_file = "init.build",
extra_build_files = ["system.build"],
Expand All @@ -218,12 +243,10 @@ Note that ``qnx_ifs`` rejects anything in ``srcs`` that does not provide a
``rules_pkg`` provider, so a plain ``filegroup`` or a bare label will not work -
wrap it in ``pkg_files``.

See `images/common/apps/BUILD <https://github.com/eclipse-score/reference_integration/blob/main/images/common/apps/BUILD>`_
and `images/qnx_x86_64/build/BUILD <https://github.com/eclipse-score/reference_integration/blob/main/images/qnx_x86_64/build/BUILD>`_
for the full picture, and repeat the equivalent wiring in the other images you
need (`images/linux_x86_64 <https://github.com/eclipse-score/reference_integration/tree/main/images/linux_x86_64>`_,
`images/autosd <https://github.com/eclipse-score/reference_integration/tree/main/images/autosd>`_,
`images/ebclfsa_aarch64 <https://github.com/eclipse-score/reference_integration/tree/main/images/ebclfsa_aarch64>`_).
See `deploy/README.md <https://github.com/eclipse-score/reference_integration/blob/main/deploy/README.md>`_
for the contract between the platform and the showcase layer, and
`images/qnx_x86_64/build/BUILD <https://github.com/eclipse-score/reference_integration/blob/main/images/qnx_x86_64/build/BUILD>`_
for how an image consumes it.

If your module simply cannot run on a given platform, exclude its targets via
``metadata.exclude_test_targets`` / ``metadata.extra_test_config`` in
Expand Down
Loading
Loading