Skip to content
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
21 changes: 10 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
# ISAR builds use kas-container with --privileged (required for mmdebstrap's
# unshare(2) mount namespace isolation). Build cache (downloads + sstate) is
# persisted via actions/cache and forwarded into the container via kas-container's
# DL_DIR/SSTATE_DIR mount mechanism, with the ci-cache.yml kas overlay ensuring
# BitBake uses the container-mounted paths.
# DL_DIR/SSTATE_DIR environment variable mount mechanism. base.yml hardcodes
# /downloads and /sstate (the stable kas-container mount points).

name: CI

Expand Down Expand Up @@ -232,6 +232,9 @@ jobs:
env:
KAS_CONTAINER_ENGINE: docker
KAS_CONTAINER_IMAGE: ghcr.io/siemens/kas/kas-isar:5.1
# CRITICAL: kas-container mounts these host paths into the container at
# /downloads and /sstate. Without these, builds use ephemeral container
# storage and lose all cached downloads between runs.
DL_DIR: ${{ github.workspace }}/.ci-cache/downloads
SSTATE_DIR: ${{ github.workspace }}/.ci-cache/sstate
MACHINE: ${{ matrix.machine }}
Expand All @@ -240,8 +243,7 @@ jobs:
set -euo pipefail

# Get all variants for this machine with CI overlays applied.
# mkCiKasCommand appends ci-cache.yml always, native-build.yml
# when host arch matches target (replaces shell case statement).
# mkCiKasCommand appends native-build.yml when host arch matches target.
HOST_ARCH=$(uname -m)
VARIANTS=$(nix eval --json '.#lib.debian.buildMatrix' --apply "
matrix: builtins.map (v: {
Expand All @@ -260,9 +262,6 @@ jobs:
echo "::group::[$((IDX + 1))/$VARIANT_COUNT] Building variant: $ID"
echo "kas command: $FULL_CMD"

# Clean stale .git-downloads symlink (kas-container tmpdir changes between sessions)
rm -f build/tmp/work/debian-trixie-*/.git-downloads 2>/dev/null || true

kas-container --isar build "$FULL_CMD"
echo "::endgroup::"
done
Expand Down Expand Up @@ -383,6 +382,9 @@ jobs:
env:
KAS_CONTAINER_ENGINE: docker
KAS_CONTAINER_IMAGE: ghcr.io/siemens/kas/kas-isar:5.1
# CRITICAL: kas-container mounts these host paths into the container at
# /downloads and /sstate. Without these, builds use ephemeral container
# storage and lose all cached downloads between runs.
DL_DIR: ${{ github.workspace }}/.ci-cache/downloads
SSTATE_DIR: ${{ github.workspace }}/.ci-cache/sstate
VARIANTS: ${{ matrix.variants }}
Expand All @@ -401,11 +403,8 @@ jobs:
")
echo "kas command: $FULL_CMD"

# Clean stale .git-downloads symlink
cd backends/debian
rm -f build/tmp/work/debian-trixie-*/.git-downloads 2>/dev/null || true

# Build
cd backends/debian
kas-container --isar build "$FULL_CMD"
cd ../..

Expand Down
26 changes: 5 additions & 21 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,28 +251,12 @@ nix develop -c bash -c "cd backends/debian && kas-container --isar cleansstate k
nix develop -c bash -c "cd backends/debian && kas-container --isar cleanall kas/machine/<machine>.yml:..."
```

**Stale `.git-downloads` symlink** (common issue):
- Each kas-container session creates a new tmpdir (`/tmp/tmpXXXXXX`); `.git-downloads` symlink in the build work dir points to the previous session's tmpdir
- **Fix**: Remove before EVERY new build after a container session change:
```bash
rm -f backends/debian/build/tmp/work/debian-trixie-arm64/.git-downloads
rm -f backends/debian/build/tmp/work/debian-trixie-amd64/.git-downloads
```
- Integrate into build command: `rm -f backends/debian/build/tmp/work/debian-trixie-*/.git-downloads && nix develop -c bash -c "cd backends/debian && kas-build ..."`

**Download cache collision** (multi-arch):
- k3s recipe uses `downloadfilename=k3s` for BOTH architectures — x86_64 and arm64 binaries share the same cache key
- If switching architectures (e.g., qemuamd64 → jetson-orin-nano), the cached `k3s` binary is the wrong architecture
- **Fix**: Delete the cached binary AND its fetch stamps:
```bash
rm -f ~/.cache/yocto/downloads/k3s ~/.cache/yocto/downloads/k3s.done
rm -f backends/debian/build/tmp/stamps/debian-trixie-arm64/k3s-server/1.32.0-r0.do_fetch*
rm -f backends/debian/build/tmp/stamps/debian-trixie-arm64/k3s-agent/1.32.0-r0.do_fetch*
```
- TODO: Fix k3s recipe to use arch-specific `downloadfilename` (e.g., `k3s-arm64` or `k3s-amd64`)

### ISAR Build Cache
- Shared cache: `DL_DIR="${HOME}/.cache/yocto/downloads"`, `SSTATE_DIR="${HOME}/.cache/yocto/sstate"`
- The kas-build wrapper (flake.nix) exports `DL_DIR` and `SSTATE_DIR` with defaults of `~/.cache/yocto/{downloads,sstate}`
- kas-container mounts these host paths at `/downloads` and `/sstate` inside the container
- base.yml hardcodes `DL_DIR = "/downloads"` and `SSTATE_DIR = "/sstate"` (the stable mount points)
- **WARNING**: Do NOT use `${HOME}` in kas `local_conf_header` — inside the container, kas overrides HOME to an ephemeral tmpdir (`/tmp/tmpXXXXXX`), so any path referencing `${HOME}` is destroyed on exit (siemens/kas#148)
- CI sets its own `DL_DIR`/`SSTATE_DIR` values which the wrapper respects via `${VAR:-default}` pattern

### ZFS Replication Limitations

Expand Down
21 changes: 16 additions & 5 deletions backends/debian/kas/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,22 @@ target: isar-image-base
# Common variables
local_conf_header:
shared-cache: |
# Shared user-level cache directories for all Yocto/ISAR projects
# This enables cache reuse across multiple projects/builds
# BitBake auto-creates these directories if they don't exist
DL_DIR = "${HOME}/.cache/yocto/downloads"
SSTATE_DIR = "${HOME}/.cache/yocto/sstate"
# Download and sstate cache paths inside the kas-container.
#
# kas-container mounts host DL_DIR at /downloads and SSTATE_DIR at /sstate
# when these environment variables are set on the host. The kas-build wrapper
# (flake.nix mkKasBuildWrapper) exports them with a default of
# ~/.cache/yocto/{downloads,sstate}, enabling cross-project cache sharing.
#
# WARNING: Do NOT use ${HOME} here. Inside the container, kas overrides HOME
# to an ephemeral tmpdir for build isolation (siemens/kas#148). Any path
# referencing ${HOME} resolves to /tmp/tmpXXXXXX and is destroyed on exit.
#
# If DL_DIR/SSTATE_DIR are not set on the host (e.g., running kas directly
# without the wrapper), these paths won't exist and BitBake will fall back
# to creating them inside the container (ephemeral). Always use the wrapper.
DL_DIR = "/downloads"
SSTATE_DIR = "/sstate"

n3x-base: |
# n3x common configuration
Expand Down
32 changes: 11 additions & 21 deletions backends/debian/kas/mirrors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,22 @@
header:
version: 14

# ISAR framework repository
# ISAR framework repository (fork with do_adjust_git symlink fix)
#
# IMPORTANT: This will eventually be a FORK, not a plain mirror.
# Fork of ilbers/isar with fix for dangling symlink handling in
# dpkg-base.bbclass do_adjust_git(). os.path.exists() follows symlinks
# and misses dangling ones, causing FileExistsError when DL_DIR mount
# paths change between kas-container sessions.
#
# ISAR's dpkg-base.bbclass has a bug in do_adjust_git (line 30-34) where
# os.path.exists() is used to check a symlink, but this follows the symlink
# target. When the target doesn't exist (stale tmpdir from a previous
# kas-container session), the dangling symlink isn't cleaned up, and the
# subsequent os.symlink() call fails with FileExistsError.
# Fix: os.path.exists() → os.path.lexists() on lines 30 and 33.
# Upstream issue: https://github.com/ilbers/isar/issues/122
# Upstream PR: https://github.com/ilbers/isar/pull/123
#
# Fix: change os.path.exists() to os.path.lexists() on line 30 and 33 of
# meta/classes-recipe/dpkg-base.bbclass in the ISAR source.
#
# Upstream file: https://github.com/ilbers/isar/blob/master/meta/classes-recipe/dpkg-base.bbclass
# Affected function: do_adjust_git() -- symlink creation for .git-downloads
#
# Current workaround: rm -f build/tmp/work/debian-trixie-*/.git-downloads
# before each kas-container build when switching between invocations.
#
# Tracking: When internal GitLab mirror is provisioned, create a fork with
# a patch branch containing the fix, point this URL at the fork, and submit
# the fix upstream to ilbers/isar.
# TODO: Revert to upstream ilbers/isar once fix is merged.
repos:
isar:
url: https://github.com/ilbers/isar.git
commit: 16b7b7e37b54be969453466e01ce4aa66e8ccb8e
url: https://github.com/kyosaku-kai/isar.git
commit: 62a2db1545a8d5dd811d3ad7caa3107fb51e256e
layers:
meta:
meta-isar:
Expand Down
26 changes: 0 additions & 26 deletions backends/debian/kas/opt/ci-cache.yml

This file was deleted.

3 changes: 0 additions & 3 deletions backends/debian/scripts/isar-build-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,6 @@ process_variant() {
if ${dry_run}; then
echo " [DRY-RUN] Would run: nix develop '.' -c bash -c \"cd backends/debian && kas-build ${full_kas_cmd}\""
else
# Clean stale .git-downloads symlink
rm -f backends/debian/build/tmp/work/debian-trixie-*/.git-downloads 2>/dev/null || true

nix develop '.' -c bash -c "cd backends/debian && kas-build ${full_kas_cmd}"
fi
fi
Expand Down
18 changes: 18 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,15 @@
log_warn "Could not detect machine from kas config — skipping arch detection"
fi

# Persistent download and sstate cache directories.
# kas-container reads these from the environment and mounts them into the
# container at /downloads and /sstate respectively. Without these exports,
# BitBake's DL_DIR inside the container resolves to kas's ephemeral tmpdir
# HOME (/tmp/tmpXXXXXX) and all downloads are lost between builds.
# See: siemens/kas#52, siemens/kas#148
export DL_DIR="''${DL_DIR:-''${HOME}/.cache/yocto/downloads}"
export SSTATE_DIR="''${SSTATE_DIR:-''${HOME}/.cache/yocto/sstate}"

export KAS_CONTAINER_IMAGE="ghcr.io/siemens/kas/kas-isar:5.1"

log_info "Starting kas-container build (engine: $KAS_CONTAINER_ENGINE)..."
Expand Down Expand Up @@ -603,6 +612,15 @@
log_info "Config: $kas_config"
echo

# Persistent download and sstate cache directories.
# kas-container reads these from the environment and mounts them into the
# container at /downloads and /sstate respectively. Without these exports,
# BitBake's DL_DIR inside the container resolves to kas's ephemeral tmpdir
# HOME (/tmp/tmpXXXXXX) and all downloads are lost between builds.
# See: siemens/kas#52, siemens/kas#148
export DL_DIR="''${DL_DIR:-''${HOME}/.cache/yocto/downloads}"
export SSTATE_DIR="''${SSTATE_DIR:-''${HOME}/.cache/yocto/sstate}"

# ISAR commit 27651d51 (Sept 2024) requires bubblewrap for rootfs sandboxing
# kas-isar:4.7 does NOT have bwrap; kas-isar:5.1+ does
# Use KAS_CONTAINER_IMAGE to override the full image path (not KAS_CONTAINER_IMAGE_NAME)
Expand Down
7 changes: 3 additions & 4 deletions lib/debian/build-matrix.nix
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,14 @@ let
# CI and release helpers
# ===========================================================================

# CI-aware kas command: appends ci-cache.yml always, native-build.yml when
# the runner's host architecture matches the target machine's architecture.
# CI-aware kas command: appends native-build.yml when the runner's host
# architecture matches the target machine's architecture.
mkCiKasCommand = { hostArch }: variant:
let
machineInfo = machines.${variant.machine};
baseCommand = mkKasCommand variant;
isNative = hostArch == machineInfo.arch;
ciOverlays = [ "kas/opt/ci-cache.yml" ]
++ lib.optional isNative "kas/opt/native-build.yml";
ciOverlays = lib.optional isNative "kas/opt/native-build.yml";
in
lib.concatStringsSep ":" ([ baseCommand ] ++ ciOverlays);

Expand Down
Loading
Loading