dey-image-container: add final artifact bundle generation
Add the artifact packaging stage that assembles deployable LXC/Podman bundles with a normalized layout (manifest, payload, checksums, metadata). The task also computes digests/metadata and removes intermediate build outputs once final artifacts are produced. https://onedigi.atlassian.net/browse/DEL-10004 Signed-off-by: Francisco Gil <francisco.gilmartinez@digi.com> Signed-off-by: Isaac Hermida <isaac.hermida@digi.com>
This commit is contained in:
parent
3efe532995
commit
2da298408e
|
|
@ -0,0 +1,236 @@
|
|||
# meta-digi-containers
|
||||
|
||||
Yocto layer for Digi container-focused image generation and packaging.
|
||||
|
||||
This layer provides the `dey-image-container` image recipe and related logic to produce:
|
||||
|
||||
- A base rootfs (`tar.xz`)
|
||||
- An OCI image output
|
||||
- A Podman archive (`*.tar`)
|
||||
- An LXC bundle (`*.tar.xz`)
|
||||
- Final container artifacts (`*.tar.gz`) with:
|
||||
- `manifest.json`
|
||||
- `payload/`
|
||||
- `checksums/sha256sums.txt`
|
||||
- optional `metadata/`
|
||||
|
||||
Note: Podman archive generation requires an OCI image output as intermediate input.
|
||||
The recipe keeps `oci` in `IMAGE_FSTYPES` because `do_image_podman_archive` converts
|
||||
that OCI artifact into a `docker-archive` tar using `skopeo`.
|
||||
|
||||
## Layer Scope
|
||||
|
||||
Main recipe:
|
||||
|
||||
- `recipes-core/images/dey-image-container.bb`
|
||||
|
||||
Recipe includes:
|
||||
|
||||
- `dey-image-container-fragments.inc`
|
||||
- `dey-image-container-lxc.inc`
|
||||
- `dey-image-container-podman.inc`
|
||||
- `dey-image-container-artifact.inc`
|
||||
|
||||
Container support files:
|
||||
|
||||
- `containers/<profile>/configs_lxc/` (profile LXC config fragments)
|
||||
- `containers/<profile>/rootfs_files/` (profile rootfs overlays)
|
||||
- `containers/<profile>/artifact/` (optional artifact metadata template)
|
||||
|
||||
## Add The Layer
|
||||
|
||||
In your build environment:
|
||||
|
||||
```bash
|
||||
bitbake-layers add-layer /path/to/sources/meta-digi/meta-digi-containers
|
||||
bitbake-layers add-layer /path/to/sources/meta-virtualization
|
||||
bitbake-layers add-layer /path/to/sources/meta-openembedded/meta-filesystems
|
||||
```
|
||||
|
||||
Or add it manually to `conf/bblayers.conf`.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Set profile and naming in `conf/local.conf`:
|
||||
|
||||
```conf
|
||||
DISTRO_FEATURES:append = " virtualization"
|
||||
CONTAINER_TYPE = "webkit" # or: lvgl, base, custom profile
|
||||
CONTAINER_NAME = "webkit-example"
|
||||
# PODMAN_TAG defaults to "${CONTAINER_NAME}-tag"
|
||||
```
|
||||
|
||||
Build:
|
||||
|
||||
```bash
|
||||
bitbake dey-image-container
|
||||
```
|
||||
|
||||
Outputs are generated in:
|
||||
|
||||
- `tmp/deploy/images/${MACHINE}/`
|
||||
|
||||
Final outputs:
|
||||
|
||||
- `${CONTAINER_NAME}_artifact_podman_${MACHINE}.tar.gz`
|
||||
- `${CONTAINER_NAME}_artifact_lxc_${MACHINE}.tar.gz`
|
||||
|
||||
Intermediate outputs generated during the build (LXC bundle, Podman archive, OCI/rootfs files)
|
||||
are removed automatically at the end of artifact creation.
|
||||
|
||||
## Profiles
|
||||
|
||||
Profile-specific behavior is controlled with:
|
||||
|
||||
- `CONTAINER_TYPE`
|
||||
- `OVERRIDES:append = ":container-${CONTAINER_TYPE}"` (handled in recipe)
|
||||
|
||||
Current built-in profile examples:
|
||||
|
||||
- `container-lvgl`
|
||||
- `container-webkit`
|
||||
|
||||
You can add new profiles by appending variables with `:container-<name>` overrides.
|
||||
|
||||
For customer-defined profiles, use:
|
||||
|
||||
```conf
|
||||
CONTAINER_TYPE = "myprofile"
|
||||
CONTAINER_NAME = "myprofile-demo"
|
||||
PODMAN_TAG = "myprofile-demo-tag"
|
||||
|
||||
IMAGE_INSTALL:append:container-myprofile = " package-a package-b"
|
||||
CONTAINER_INIT_MANAGER:container-myprofile = "/usr/bin/docker-init"
|
||||
CONTAINER_INIT_SCRIPT:container-myprofile = "/usr/bin/my-app --foreground"
|
||||
|
||||
# Manifest-related overrides can also be profile-specific:
|
||||
CONTAINER_ARTIFACT_VERSION:container-myprofile = "1.2.0"
|
||||
CONTAINER_FIRMWARE_VERSIONS:container-myprofile = ">=25.01"
|
||||
CONTAINER_DEVICE_TYPES_JSON:container-myprofile = "[\"ccmp25-dvk\"]"
|
||||
CONTAINER_ARTIFACT_DESCRIPTION:container-myprofile = "My profile demo container"
|
||||
CONTAINER_ARTIFACT_LABELS_JSON:container-myprofile = "{\"vendor\":\"digi\",\"component\":\"demo\"}"
|
||||
|
||||
```
|
||||
|
||||
## Rootfs Overlay
|
||||
|
||||
Use the following variables to inject directories into the container rootfs:
|
||||
|
||||
```conf
|
||||
CONTAINER_ROOTFS_OVERLAY_DIRS = "/absolute/path/to/overlay"
|
||||
CONTAINER_ROOTFS_OVERLAY_TARBALLS = "/absolute/path/to/overlay.tar.gz"
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Multiple entries are supported (space-separated).
|
||||
- `*.sh` files copied from overlay directories are marked executable automatically.
|
||||
- If `CONTAINER_ROOTFS_OVERLAY_DIRS` is not set
|
||||
and `containers/${CONTAINER_TYPE}/rootfs_files` exists,
|
||||
it is used automatically.
|
||||
|
||||
## LXC Fragment Configuration
|
||||
|
||||
LXC fragments are loaded from:
|
||||
|
||||
- `containers/${CONTAINER_TYPE}/configs_lxc/`
|
||||
|
||||
Config file naming:
|
||||
|
||||
- `config_lxc_<machine>`
|
||||
|
||||
Example:
|
||||
|
||||
- `config_lxc_ccmp25-dvk`
|
||||
|
||||
`<machine>` matches the full `MACHINE` value.
|
||||
|
||||
Supported placeholders in LXC config fragments:
|
||||
|
||||
- `@LXC_ARCH@`
|
||||
- `@LXC_FOLDER@`
|
||||
- `@CONTAINER_NAME@`
|
||||
- `@CONTAINER_INIT_MANAGER@`
|
||||
- `@CONTAINER_INIT_SCRIPT@`
|
||||
|
||||
## Artifact Manifest Fields
|
||||
|
||||
The artifact manifest is generated automatically and includes:
|
||||
|
||||
- `package_id`
|
||||
- `version`
|
||||
- `runtime`
|
||||
- `artifact_type`
|
||||
- `create_args` [optional] for Podman artifacts (only when non-empty)
|
||||
- `created_at`
|
||||
- `digest`
|
||||
- `device_types`
|
||||
- `firmware_versions`
|
||||
- `size_bytes`
|
||||
- `build_id`
|
||||
- `description`
|
||||
- `labels`
|
||||
|
||||
`build_id` behavior:
|
||||
|
||||
- Uses `CONTAINER_ARTIFACT_BUILD_ID` if explicitly set.
|
||||
- Otherwise uses the current `meta-digi` git commit SHA (`git rev-parse HEAD`).
|
||||
|
||||
Relevant variables:
|
||||
|
||||
- `CONTAINER_PACKAGE_ID`
|
||||
- `CONTAINER_ARTIFACT_VERSION`
|
||||
- `CONTAINER_CREATE_ARGS_PODMAN`
|
||||
- `CONTAINER_FIRMWARE_VERSIONS`
|
||||
- `CONTAINER_DEVICE_TYPES_JSON`
|
||||
- `CONTAINER_ARTIFACT_DESCRIPTION`
|
||||
- `CONTAINER_ARTIFACT_BUILD_ID`
|
||||
- `CONTAINER_ARTIFACT_LABELS_JSON`
|
||||
|
||||
## Optional Artifact Metadata Template
|
||||
|
||||
If you set:
|
||||
|
||||
```conf
|
||||
CONTAINER_ARTIFACT_TEMPLATE_DIR = "/path/to/artifact-template"
|
||||
```
|
||||
|
||||
and the template contains `metadata/`, it is copied into final artifact bundles.
|
||||
|
||||
`manifest.json`, `payload/*`, and `checksums/sha256sums.txt` are always generated during
|
||||
build time and should not be pre-created in the template.
|
||||
|
||||
If `CONTAINER_ARTIFACT_TEMPLATE_DIR` is not set and `containers/${CONTAINER_TYPE}/artifact` exists,
|
||||
it is used automatically.
|
||||
|
||||
## Container Folder Layout
|
||||
|
||||
Each profile is self-contained under `containers/`:
|
||||
|
||||
```text
|
||||
containers/
|
||||
lvgl/
|
||||
rootfs_files/
|
||||
configs_lxc/
|
||||
artifact/
|
||||
webkit/
|
||||
rootfs_files/
|
||||
configs_lxc/
|
||||
artifact/
|
||||
custom/
|
||||
rootfs_files/
|
||||
configs_lxc/
|
||||
artifact/
|
||||
```
|
||||
|
||||
To create a new profile:
|
||||
|
||||
1. Create `containers/<profile>/configs_lxc/config_lxc_<machine>`.
|
||||
2. Optionally add `containers/<profile>/rootfs_files/` for rootfs content.
|
||||
3. Set `CONTAINER_TYPE = "<profile>"` in `local.conf`.
|
||||
4. Add profile packages with `IMAGE_INSTALL:append:container-<profile> = " ... "`.
|
||||
|
||||
## Notes
|
||||
|
||||
- Intermediate container artifacts from the current build are removed at the end of the artifact task.
|
||||
- If `dey-image-container` is not found, verify the layer is present in `BBLAYERS`.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Placeholder metadata for custom container artifacts.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Placeholder changelog for custom container artifacts.
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# LXC base config for custom profile on CCIMX95.
|
||||
# Placeholders are replaced by the image recipe.
|
||||
lxc.arch = @LXC_ARCH@
|
||||
lxc.rootfs.path = dir:@LXC_FOLDER@/@CONTAINER_NAME@/rootfs
|
||||
lxc.uts.name = @CONTAINER_NAME@
|
||||
|
||||
lxc.mount.auto = cgroup:mixed proc:mixed
|
||||
lxc.mount.entry = /sys sys none bind,create=dir
|
||||
lxc.mount.entry = tmpfs run tmpfs rw,nosuid,nodev,mode=0755,create=dir
|
||||
|
||||
# custom prompt
|
||||
lxc.environment = 'PS1=\h:\w$ '
|
||||
|
||||
# no network
|
||||
lxc.net.0.type = empty
|
||||
|
||||
lxc.init.cmd = @CONTAINER_INIT_MANAGER@ @CONTAINER_INIT_SCRIPT@
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# LXC base config for custom profile on CCMP25.
|
||||
# Placeholders are replaced by the image recipe.
|
||||
lxc.arch = @LXC_ARCH@
|
||||
lxc.rootfs.path = dir:@LXC_FOLDER@/@CONTAINER_NAME@/rootfs
|
||||
lxc.uts.name = @CONTAINER_NAME@
|
||||
|
||||
lxc.mount.auto = cgroup:mixed proc:mixed
|
||||
lxc.mount.entry = /sys sys none bind,create=dir
|
||||
lxc.mount.entry = tmpfs run tmpfs rw,nosuid,nodev,mode=0755,create=dir
|
||||
|
||||
# custom prompt
|
||||
lxc.environment = 'PS1=\h:\w$ '
|
||||
|
||||
# no network
|
||||
lxc.net.0.type = empty
|
||||
|
||||
lxc.init.cmd = @CONTAINER_INIT_MANAGER@ @CONTAINER_INIT_SCRIPT@
|
||||
|
|
@ -0,0 +1 @@
|
|||
Placeholder metadata for lvgl container artifacts.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Placeholder changelog for lvgl container artifacts.
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# LXC config for LVGL on CCIMX95.
|
||||
# Placeholders are replaced by the image recipe.
|
||||
lxc.arch = @LXC_ARCH@
|
||||
lxc.rootfs.path = dir:@LXC_FOLDER@/@CONTAINER_NAME@/rootfs
|
||||
lxc.uts.name = @CONTAINER_NAME@
|
||||
|
||||
lxc.mount.auto = cgroup:mixed proc:mixed
|
||||
lxc.mount.entry = /sys sys none bind,create=dir
|
||||
lxc.mount.entry = tmpfs run tmpfs rw,nosuid,nodev,mode=0755,create=dir
|
||||
|
||||
# custom prompt
|
||||
lxc.environment = 'PS1=\h:\w$ '
|
||||
|
||||
# no network
|
||||
lxc.net.0.type = empty
|
||||
|
||||
lxc.init.cmd = @CONTAINER_INIT_MANAGER@ @CONTAINER_INIT_SCRIPT@
|
||||
lxc.mount.entry = /dev/dri dev/dri none bind,create=dir
|
||||
lxc.mount.entry = /dev/input dev/input none bind,create=dir
|
||||
lxc.mount.entry = tmpfs dev/shm tmpfs rw,nosuid,nodev,mode=1777,create=dir
|
||||
lxc.mount.entry = /dev/dri dev/dri none bind,create=dir
|
||||
lxc.mount.entry = /dev/mali0 dev/mali0 none bind,create=file
|
||||
lxc.mount.entry = /dev/input dev/input none bind,create=dir
|
||||
lxc.mount.entry = /dev/tty dev/tty none bind,create=file
|
||||
lxc.mount.entry = /dev/tty0 dev/tty0 none bind,create=file
|
||||
lxc.mount.entry = /dev/tty1 dev/tty1 none bind,create=file
|
||||
lxc.mount.entry = /dev/tty7 dev/tty7 none bind,create=file
|
||||
lxc.mount.entry = /run/udev run/udev none bind,ro,create=dir
|
||||
lxc.pty.max = 1024
|
||||
lxc.mount.entry = devpts dev/pts devpts rw,nosuid,noexec,relatime,mode=0620,ptmxmod
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# LXC config for LVGL on CCMP25.
|
||||
# Placeholders are replaced by the image recipe.
|
||||
lxc.arch = @LXC_ARCH@
|
||||
lxc.rootfs.path = dir:@LXC_FOLDER@/@CONTAINER_NAME@/rootfs
|
||||
lxc.uts.name = @CONTAINER_NAME@
|
||||
|
||||
lxc.mount.auto = cgroup:mixed proc:mixed
|
||||
lxc.mount.entry = /sys sys none bind,create=dir
|
||||
lxc.mount.entry = tmpfs run tmpfs rw,nosuid,nodev,mode=0755,create=dir
|
||||
|
||||
# custom prompt
|
||||
lxc.environment = 'PS1=\h:\w$ '
|
||||
|
||||
# no network
|
||||
lxc.net.0.type = empty
|
||||
|
||||
lxc.init.cmd = @CONTAINER_INIT_MANAGER@ @CONTAINER_INIT_SCRIPT@
|
||||
lxc.mount.entry = tmpfs dev/shm tmpfs rw,nosuid,nodev,mode=1777,create=dir
|
||||
lxc.mount.entry = /dev/dri dev/dri none bind,create=dir
|
||||
lxc.mount.entry = /dev/input dev/input none bind,create=dir
|
||||
lxc.mount.entry = /dev/dri dev/dri none bind,create=dir
|
||||
lxc.mount.entry = /dev/galcore dev/galcore none bind,create=file
|
||||
lxc.mount.entry = /dev/input dev/input none bind,create=dir
|
||||
lxc.mount.entry = /dev/tty dev/tty none bind,create=file
|
||||
lxc.mount.entry = /dev/tty0 dev/tty0 none bind,create=file
|
||||
lxc.mount.entry = /dev/tty1 dev/tty1 none bind,create=file
|
||||
lxc.mount.entry = /dev/tty7 dev/tty7 none bind,create=file
|
||||
lxc.mount.entry = /run/udev run/udev none bind,ro,create=dir
|
||||
lxc.pty.max = 1024
|
||||
lxc.mount.entry = devpts dev/pts devpts rw,nosuid,noexec,relatime,mode=0620,ptmxmod
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/sh
|
||||
export XDG_RUNTIME_DIR="/run/user/0"
|
||||
export WAYLAND_DISPLAY="@WAYLAND_DISPLAY@"
|
||||
|
||||
rm -rf "$XDG_RUNTIME_DIR"
|
||||
mkdir -p "$XDG_RUNTIME_DIR"
|
||||
chmod 0700 "$XDG_RUNTIME_DIR"
|
||||
chown root:root "$XDG_RUNTIME_DIR"
|
||||
|
||||
rm -rf /tmp/.X11-unix
|
||||
mkdir -p /tmp/.X11-unix
|
||||
chmod 1777 /tmp/.X11-unix
|
||||
|
||||
rm -f /tmp/weston.log
|
||||
|
||||
weston --backend=drm-backend.so --idle-time=0 --log=/tmp/weston.log &
|
||||
|
||||
while :; do
|
||||
if [ -S "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
sleep 0.1
|
||||
|
||||
exec /usr/bin/lvgl-demo
|
||||
|
|
@ -0,0 +1 @@
|
|||
Placeholder metadata for webkit container artifacts.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Placeholder changelog for webkit container artifacts.
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
# LXC config for WebKit on CCIMX95.
|
||||
# Placeholders are replaced by the image recipe.
|
||||
lxc.arch = @LXC_ARCH@
|
||||
lxc.rootfs.path = dir:@LXC_FOLDER@/@CONTAINER_NAME@/rootfs
|
||||
lxc.uts.name = @CONTAINER_NAME@
|
||||
|
||||
lxc.mount.auto = cgroup:mixed proc:mixed
|
||||
lxc.mount.entry = /sys sys none bind,create=dir
|
||||
lxc.mount.entry = tmpfs run tmpfs rw,nosuid,nodev,mode=0755,create=dir
|
||||
|
||||
# use host network
|
||||
lxc.net.0.type = none
|
||||
|
||||
lxc.init.cmd = @CONTAINER_INIT_MANAGER@ @CONTAINER_INIT_SCRIPT@
|
||||
lxc.environment = 'PS1=webkit-ccimx95:\w$ '
|
||||
|
||||
# audio
|
||||
lxc.mount.entry = /dev/snd dev/snd none bind,create=dir
|
||||
lxc.mount.entry = /etc/asound.conf etc/asound.conf none bind,create=file
|
||||
lxc.mount.entry = /run/pulse run/pulse none bind,create=dir
|
||||
lxc.environment = PULSE_SERVER=unix:/run/pulse/native
|
||||
|
||||
# bluetooth
|
||||
lxc.mount.entry = /run/dbus/system_bus_socket run/dbus/system_bus_socket none bind,create=file
|
||||
|
||||
# python logging
|
||||
lxc.mount.entry = /dev/log dev/log none bind,create=file
|
||||
lxc.mount.entry = /run/systemd/journal run/systemd/journal none bind,create=dir
|
||||
|
||||
# fw_printenv
|
||||
lxc.mount.entry = /etc/fw_env.config etc/fw_env.config none bind,create=file
|
||||
lxc.mount.entry = /dev/mmcblk0boot0 dev/mmcblk0boot0 none bind,optional,create=file
|
||||
lxc.mount.entry = /dev/mmcblk0boot1 dev/mmcblk0boot1 none bind,optional,create=file
|
||||
|
||||
# gpu for ccimx95
|
||||
lxc.mount.entry = /dev/dri dev/dri none bind,create=dir
|
||||
lxc.mount.entry = /dev/galcore dev/galcore none bind,create=file
|
||||
lxc.mount.entry = /dev/fb0 dev/fb0 none bind,create=file
|
||||
lxc.mount.entry = /dev/input dev/input none bind,create=dir
|
||||
|
||||
# tty
|
||||
lxc.mount.entry = /dev/tty dev/tty none bind,create=file
|
||||
lxc.mount.entry = /dev/tty0 dev/tty0 none bind,create=file
|
||||
lxc.mount.entry = /dev/tty1 dev/tty1 none bind,create=file
|
||||
lxc.mount.entry = /dev/tty7 dev/tty7 none bind,create=file
|
||||
|
||||
# udev + pty
|
||||
lxc.mount.entry = /run/udev run/udev none bind,ro,create=dir
|
||||
lxc.pty.max = 1024
|
||||
lxc.mount.entry = devpts dev/pts devpts rw,nosuid,noexec,relatime,mode=0620,ptmxmode=0666,newinstance 0 0
|
||||
|
||||
# gpiochip access for webkit demo
|
||||
# NEED TO BE UPDATED
|
||||
lxc.mount.entry = /dev/gpiochip5 dev/gpiochip5 none bind,create=file
|
||||
lxc.mount.entry = /dev/gpiochip5 dev/gpiochip5 none bind,create=file
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
# LXC config for WebKit on CCMP25.
|
||||
# Placeholders are replaced by the image recipe.
|
||||
lxc.arch = @LXC_ARCH@
|
||||
lxc.rootfs.path = dir:@LXC_FOLDER@/@CONTAINER_NAME@/rootfs
|
||||
lxc.uts.name = @CONTAINER_NAME@
|
||||
|
||||
lxc.mount.auto = cgroup:mixed proc:mixed
|
||||
lxc.mount.entry = /sys sys none bind,create=dir
|
||||
lxc.mount.entry = tmpfs run tmpfs rw,nosuid,nodev,mode=0755,create=dir
|
||||
|
||||
# use host network
|
||||
lxc.net.0.type = none
|
||||
|
||||
lxc.init.cmd = @CONTAINER_INIT_MANAGER@ @CONTAINER_INIT_SCRIPT@
|
||||
lxc.environment = 'PS1=webkit-ccmp25:\w$ '
|
||||
|
||||
# audio
|
||||
lxc.mount.entry = /dev/snd dev/snd none bind,create=dir
|
||||
lxc.mount.entry = /etc/asound.conf etc/asound.conf none bind,create=file
|
||||
lxc.mount.entry = /run/pulse run/pulse none bind,create=dir
|
||||
lxc.environment = PULSE_SERVER=unix:/run/pulse/native
|
||||
|
||||
# bluetooth
|
||||
lxc.mount.entry = /run/dbus/system_bus_socket run/dbus/system_bus_socket none bind,create=file
|
||||
|
||||
# python logging
|
||||
lxc.mount.entry = /dev/log dev/log none bind,create=file
|
||||
lxc.mount.entry = /run/systemd/journal run/systemd/journal none bind,create=dir
|
||||
|
||||
# fw_printenv
|
||||
lxc.mount.entry = /etc/fw_env.config etc/fw_env.config none bind,create=file
|
||||
lxc.mount.entry = /dev/mmcblk0boot0 dev/mmcblk0boot0 none bind,create=file
|
||||
lxc.mount.entry = /dev/mmcblk0boot1 dev/mmcblk0boot1 none bind,create=file
|
||||
|
||||
# gpu for ccmp25
|
||||
lxc.mount.entry = /dev/dri dev/dri none bind,create=dir
|
||||
lxc.mount.entry = /dev/galcore dev/galcore none bind,create=file
|
||||
lxc.mount.entry = /dev/fb0 dev/fb0 none bind,create=file
|
||||
lxc.mount.entry = /dev/input dev/input none bind,create=dir
|
||||
|
||||
# tty
|
||||
lxc.mount.entry = /dev/tty dev/tty none bind,create=file
|
||||
lxc.mount.entry = /dev/tty0 dev/tty0 none bind,create=file
|
||||
lxc.mount.entry = /dev/tty1 dev/tty1 none bind,create=file
|
||||
lxc.mount.entry = /dev/tty7 dev/tty7 none bind,create=file
|
||||
|
||||
# udev + pty
|
||||
lxc.mount.entry = /run/udev run/udev none bind,ro,create=dir
|
||||
lxc.pty.max = 1024
|
||||
lxc.mount.entry = devpts dev/pts devpts rw,nosuid,noexec,relatime,mode=0620,ptmxmode=0666,newinstance 0 0
|
||||
|
||||
# gpiochip access for webkit demo
|
||||
lxc.mount.entry = /dev/gpiochip5 dev/gpiochip5 none bind,create=file
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/sh
|
||||
export XDG_RUNTIME_DIR="/run/user/0"
|
||||
export WAYLAND_DISPLAY="@WAYLAND_DISPLAY@"
|
||||
|
||||
rm -rf "$XDG_RUNTIME_DIR"
|
||||
mkdir -p "$XDG_RUNTIME_DIR"
|
||||
chmod 0700 "$XDG_RUNTIME_DIR"
|
||||
chown root:root "$XDG_RUNTIME_DIR"
|
||||
|
||||
rm -rf /tmp/.X11-unix
|
||||
mkdir -p /tmp/.X11-unix
|
||||
chmod 1777 /tmp/.X11-unix
|
||||
|
||||
rm -f /tmp/weston.log
|
||||
|
||||
weston --backend=drm-backend.so --idle-time=0 --log=/tmp/weston.log &
|
||||
|
||||
while :; do
|
||||
if [ -S "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
sleep 0.1
|
||||
|
||||
/etc/connectcore-demo-server start
|
||||
|
||||
# wait for server to be ready
|
||||
until nc -w 1 localhost 9090 </dev/null >/dev/null 2>&1; do
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
/etc/connectcore-demo-example-webkit start
|
||||
# We need a process waiting indefinetily, if not the "init" process dies
|
||||
# and there is not any remaining process
|
||||
exec /usr/bin/docker-init -- sleep infinity
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
#
|
||||
# Copyright (C) 2026, Digi International Inc.
|
||||
#
|
||||
########################
|
||||
# Unified artifact bundles
|
||||
########################
|
||||
do_image_container_artifacts() {
|
||||
lxc_bundle="${DEPLOY_DIR_IMAGE}/${LXC_OUTPUT_NAME}"
|
||||
podman_archive="${DEPLOY_DIR_IMAGE}/${PODMAN_OUTPUT_NAME}"
|
||||
template_dir="${CONTAINER_ARTIFACT_TEMPLATE_DIR}"
|
||||
default_template_dir="${CONTAINER_DEFAULT_ARTIFACT_TEMPLATE_DIR}"
|
||||
image_prefix="${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}"
|
||||
workdir="$(mktemp -d)"
|
||||
trap 'rm -rf "${workdir}"' EXIT
|
||||
|
||||
if [ -z "${template_dir}" ] && [ -d "${default_template_dir}" ]; then
|
||||
template_dir="${default_template_dir}"
|
||||
bbnote "Using default artifact template dir: ${default_template_dir}"
|
||||
fi
|
||||
|
||||
if [ ! -f "${lxc_bundle}" ]; then
|
||||
bbfatal "Expected LXC bundle not found: ${lxc_bundle}"
|
||||
fi
|
||||
if [ ! -f "${podman_archive}" ]; then
|
||||
bbfatal "Expected Podman archive not found: ${podman_archive}"
|
||||
fi
|
||||
|
||||
copy_template_files() {
|
||||
artifact_dir="$1"
|
||||
|
||||
if [ -z "${template_dir}" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ ! -d "${template_dir}" ]; then
|
||||
bbfatal "CONTAINER_ARTIFACT_TEMPLATE_DIR does not exist: ${template_dir}"
|
||||
fi
|
||||
|
||||
if [ -d "${template_dir}/metadata" ]; then
|
||||
cp -a "${template_dir}/metadata" "${artifact_dir}/metadata"
|
||||
fi
|
||||
}
|
||||
|
||||
json_escape() {
|
||||
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
|
||||
}
|
||||
|
||||
write_manifest() {
|
||||
artifact_dir="$1"
|
||||
runtime="$2"
|
||||
artifact_type="$3"
|
||||
payload_name="$4"
|
||||
digest="$5"
|
||||
size_bytes="$6"
|
||||
created_at="$7"
|
||||
create_args="$8"
|
||||
build_id="$9"
|
||||
|
||||
package_id_esc="$(json_escape "${CONTAINER_PACKAGE_ID}")"
|
||||
version_esc="$(json_escape "${CONTAINER_ARTIFACT_VERSION}")"
|
||||
create_args_esc="$(json_escape "${create_args}")"
|
||||
fw_versions_esc="$(json_escape "${CONTAINER_FIRMWARE_VERSIONS}")"
|
||||
description_esc="$(json_escape "${CONTAINER_ARTIFACT_DESCRIPTION}")"
|
||||
build_id_esc="$(json_escape "${build_id}")"
|
||||
|
||||
printf '%s\n' \
|
||||
'{' \
|
||||
" \"package_id\": \"${package_id_esc}\"," \
|
||||
" \"version\": \"${version_esc}\"," \
|
||||
" \"runtime\": \"${runtime}\"," \
|
||||
" \"artifact_type\": \"${artifact_type}\"," \
|
||||
> "${artifact_dir}/manifest.json"
|
||||
|
||||
if [ -n "${create_args}" ]; then
|
||||
printf '%s\n' " \"create_args\": \"${create_args_esc}\"," >> "${artifact_dir}/manifest.json"
|
||||
fi
|
||||
|
||||
printf '%s\n' \
|
||||
" \"created_at\": \"${created_at}\"," \
|
||||
" \"digest\": \"sha256:${digest}\"," \
|
||||
" \"device_types\": ${CONTAINER_DEVICE_TYPES_JSON}," \
|
||||
" \"firmware_versions\": \"${fw_versions_esc}\"," \
|
||||
" \"size_bytes\": ${size_bytes}," \
|
||||
" \"build_id\": \"${build_id_esc}\"," \
|
||||
" \"description\": \"${description_esc}\"," \
|
||||
" \"labels\": ${CONTAINER_ARTIFACT_LABELS_JSON}" \
|
||||
'}' \
|
||||
>> "${artifact_dir}/manifest.json"
|
||||
}
|
||||
|
||||
create_artifact_bundle() {
|
||||
runtime="$1"
|
||||
src_payload="$2"
|
||||
payload_name="$3"
|
||||
output_name="$4"
|
||||
mode="$5"
|
||||
artifact_type="$6"
|
||||
create_args="$7"
|
||||
bundle_dir="${workdir}/bundle-${runtime}"
|
||||
artifact_dir="${bundle_dir}"
|
||||
|
||||
rm -rf "${bundle_dir}"
|
||||
mkdir -p "${artifact_dir}/payload" "${artifact_dir}/checksums"
|
||||
|
||||
copy_template_files "${artifact_dir}"
|
||||
|
||||
if [ "${mode}" = "lxc" ]; then
|
||||
lxc_unpack="${workdir}/lxc-unpack"
|
||||
rm -rf "${lxc_unpack}"
|
||||
mkdir -p "${lxc_unpack}"
|
||||
tar -xJf "${src_payload}" -C "${lxc_unpack}"
|
||||
|
||||
if [ ! -d "${lxc_unpack}/${CONTAINER_NAME}/rootfs" ] || [ ! -f "${lxc_unpack}/${CONTAINER_NAME}/config" ]; then
|
||||
bbfatal "LXC bundle does not contain expected ${CONTAINER_NAME}/rootfs and ${CONTAINER_NAME}/config"
|
||||
fi
|
||||
|
||||
tar -C "${lxc_unpack}/${CONTAINER_NAME}" \
|
||||
-czf "${artifact_dir}/payload/${payload_name}" \
|
||||
rootfs config
|
||||
else
|
||||
cp "${src_payload}" "${artifact_dir}/payload/${payload_name}"
|
||||
fi
|
||||
|
||||
digest="$(sha256sum "${artifact_dir}/payload/${payload_name}" | awk '{print $1}')"
|
||||
size_bytes="$(stat -c %s "${artifact_dir}/payload/${payload_name}")"
|
||||
created_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
build_id="${CONTAINER_ARTIFACT_BUILD_ID}"
|
||||
if [ -z "${build_id}" ]; then
|
||||
if command -v git >/dev/null 2>&1; then
|
||||
build_id="$(git -C "${META_DIGI_REPO_DIR}" rev-parse HEAD 2>/dev/null || true)"
|
||||
fi
|
||||
fi
|
||||
printf '%s %s\n' "${digest}" "payload/${payload_name}" > "${artifact_dir}/checksums/sha256sums.txt"
|
||||
write_manifest "${artifact_dir}" "${runtime}" "${artifact_type}" "${payload_name}" "${digest}" "${size_bytes}" "${created_at}" "${create_args}" "${build_id}"
|
||||
|
||||
tar -C "${bundle_dir}" -czf "${DEPLOY_DIR_IMAGE}/${output_name}" .
|
||||
|
||||
if [ ! -s "${DEPLOY_DIR_IMAGE}/${output_name}" ]; then
|
||||
bbfatal "Container artifact bundle not generated correctly: ${DEPLOY_DIR_IMAGE}/${output_name}"
|
||||
fi
|
||||
|
||||
bbnote "Container ${runtime} artifact ready: ${DEPLOY_DIR_IMAGE}/${output_name}"
|
||||
}
|
||||
|
||||
create_artifact_bundle "lxc" "${lxc_bundle}" "rootfs_and_config.tgz" "${LXC_ARTIFACT_OUTPUT_NAME}" "lxc" "lxc-tgz" ""
|
||||
create_artifact_bundle "podman" "${podman_archive}" "image.tar" "${PODMAN_ARTIFACT_OUTPUT_NAME}" "podman" "podman-image-tar" "${CONTAINER_CREATE_ARGS_PODMAN}"
|
||||
|
||||
bbnote "Removing intermediate container artifacts from this build..."
|
||||
rm -f "${lxc_bundle}" "${podman_archive}"
|
||||
rm -f "${image_prefix}.tar.xz" "${image_prefix}.rootfs-oci.tar" "${image_prefix}.rootfs-oci-dir.tar"
|
||||
rm -rf "${image_prefix}.rootfs-oci"
|
||||
}
|
||||
|
||||
addtask image_container_artifacts after do_image_lxc_bundle do_image_podman_archive before do_build
|
||||
|
|
@ -25,7 +25,7 @@ do_image_lxc_bundle() {
|
|||
|
||||
config_in="${LXC_CONFIG_FILE}"
|
||||
if [ ! -f "${config_in}" ]; then
|
||||
bbfatal "LXC config file not found for CONTAINER_TYPE='${CONTAINER_TYPE}' and platform='${LXC_PLATFORM}': ${config_in}"
|
||||
bbfatal "LXC config file not found for CONTAINER_TYPE='${CONTAINER_TYPE}' and MACHINE='${MACHINE}': ${config_in}"
|
||||
fi
|
||||
|
||||
sed \
|
||||
|
|
|
|||
|
|
@ -48,11 +48,10 @@ PODMAN_ARTIFACT_OUTPUT_NAME ?= "${CONTAINER_NAME}_artifact_podman_${MACHINE}.tar
|
|||
########################
|
||||
CONTAINERS_DIR ?= "${THISDIR}/../../containers"
|
||||
LXC_FOLDER ?= "/var/lib/lxc"
|
||||
LXC_PLATFORM ?= "${@d.getVar('MACHINE').split('-')[0]}"
|
||||
LXC_OUTPUT_NAME ?= "${CONTAINER_NAME}_lxc_${MACHINE}.tar.xz"
|
||||
LXC_ARTIFACT_OUTPUT_NAME ?= "${CONTAINER_NAME}_artifact_lxc_${MACHINE}.tar.gz"
|
||||
LXC_CONFIG_DIR ?= "${CONTAINER_PROFILE_DIR}/configs_lxc"
|
||||
LXC_CONFIG_FILE ?= "${LXC_CONFIG_DIR}/config_lxc_${LXC_PLATFORM}"
|
||||
LXC_CONFIG_FILE ?= "${LXC_CONFIG_DIR}/config_lxc_${MACHINE}"
|
||||
|
||||
########################
|
||||
# Artifact layout knobs
|
||||
|
|
@ -95,3 +94,33 @@ IMAGE_INSTALL = " \
|
|||
netbase \
|
||||
tini \
|
||||
"
|
||||
|
||||
########################
|
||||
# Container type customizations LVGL
|
||||
########################
|
||||
CONTAINER_INIT_SCRIPT:container-lvgl = "/start-lvgl-demo.sh"
|
||||
IMAGE_INSTALL:append:container-lvgl = " lvgl-demo weston"
|
||||
DISTRO_FEATURES:remove:container-lvgl = " wayland"
|
||||
|
||||
########################
|
||||
# Container type customizations webkit
|
||||
########################
|
||||
CONTAINER_INIT_SCRIPT:container-webkit = "/start-webkit-demo.sh"
|
||||
IMAGE_INSTALL:append:container-webkit = " \
|
||||
alsa-utils \
|
||||
bluez5 \
|
||||
connectcore-demo-example \
|
||||
dbus \
|
||||
libdrm \
|
||||
libgpiod-tools \
|
||||
libinput \
|
||||
libubootenv-bin \
|
||||
mesa \
|
||||
networkmanager-nmcli \
|
||||
packagegroup-dey-webkit \
|
||||
pulseaudio-server \
|
||||
python3-dbus \
|
||||
wayland \
|
||||
wayland-protocols \
|
||||
weston \
|
||||
"
|
||||
|
|
|
|||
Loading…
Reference in New Issue