diff --git a/meta-digi-containers/README.md b/meta-digi-containers/README.md index d128644ae..77e61e541 100644 --- a/meta-digi-containers/README.md +++ b/meta-digi-containers/README.md @@ -68,8 +68,10 @@ The script generates exactly one runtime artifact per execution. Notes: - `--output-dir` is optional. If omitted, the script writes the DCP to the current directory. -- The generator appends a unique suffix to the input `package_id` using the - `created_at` timestamp encoded in base36 milliseconds. +- If the input manifest omits `package_id`, the generator derives the final + `package_id` from `name` and appends a unique suffix using the `created_at` + timestamp encoded in base36 milliseconds. +- If the input manifest provides `package_id`, that value is kept unchanged. - The output file name is always derived from the generated package ID and manifest fields as: - `_artifact__.tar.gz` @@ -96,9 +98,10 @@ This generates a bundle named like: In those manifests: -- `package_id` is the base identifier used to derive the final unique DCP package ID. - `name` is the stable logical container name stored on the target. - `friendly_name` is the user-facing label shown by DRM and the manager output when available. +- the final `package_id` is generated automatically from `name` unless the + input manifest provides an explicit `package_id` ## Digi Remote Manager metrics support @@ -200,16 +203,18 @@ Outputs are generated in: Final outputs: -- `${CONTAINER_PACKAGE_ID}-_artifact_podman_.tar.gz` -- `${CONTAINER_PACKAGE_ID}-_artifact_lxc_.tar.gz` +- `${CONTAINER_NAME}-_artifact_podman_.tar.gz` +- `${CONTAINER_NAME}-_artifact_lxc_.tar.gz` Notes: -- The generator script appends a base36-encoded millisecond timestamp suffix to - the input `package_id`, stores that generated value in the final - `manifest.json`, and uses it in the DCP file name. -- In Yocto builds, `CONTAINER_PACKAGE_ID` defaults to `${CONTAINER_NAME}` before - the generator adds the unique suffix. +- The generator script derives `package_id` from the input `name` only when the + manifest does not provide one explicitly. In that default case it appends a + base36-encoded millisecond timestamp suffix, stores the generated `package_id` + in the final `manifest.json`, and uses it in the DCP file name. +- In Yocto builds, `dey-image-container` does not set `package_id`, so the + generated value always starts from `${CONTAINER_NAME}` before the generator + adds the unique suffix. Intermediate outputs generated during the build (LXC bundle, Podman archive, OCI/rootfs files) are removed automatically at the end of artifact creation. @@ -318,7 +323,6 @@ The artifact manifest is generated automatically and includes: Relevant variables: - `CONTAINER_NAME` -- `CONTAINER_PACKAGE_ID` - `CONTAINER_FRIENDLY_NAME` - `CONTAINER_ARTIFACT_VERSION` - `CONTAINER_CREATE_ARGS_PODMAN` diff --git a/meta-digi-containers/examples/manifest-lxc.json b/meta-digi-containers/examples/manifest-lxc.json index c2ea293dd..7dc3493eb 100644 --- a/meta-digi-containers/examples/manifest-lxc.json +++ b/meta-digi-containers/examples/manifest-lxc.json @@ -1,5 +1,4 @@ { - "package_id": "flutter-demo", "name": "flutter-demo", "friendly_name": "Flutter Demo", "version": "1.0", diff --git a/meta-digi-containers/examples/manifest-podman.json b/meta-digi-containers/examples/manifest-podman.json index 7081a0bb7..e5a0b68c9 100644 --- a/meta-digi-containers/examples/manifest-podman.json +++ b/meta-digi-containers/examples/manifest-podman.json @@ -1,5 +1,4 @@ { - "package_id": "flutter-demo", "name": "flutter-demo", "friendly_name": "Flutter Demo", "version": "1.0", diff --git a/meta-digi-containers/recipes-core/images/dey-image-container-artifact.inc b/meta-digi-containers/recipes-core/images/dey-image-container-artifact.inc index ffc1c2e7e..433d5541f 100644 --- a/meta-digi-containers/recipes-core/images/dey-image-container-artifact.inc +++ b/meta-digi-containers/recipes-core/images/dey-image-container-artifact.inc @@ -47,7 +47,6 @@ do_image_container_artifacts() { manifest_path="$2" create_args="$3" build_id="$4" - PACKAGE_ID="${CONTAINER_PACKAGE_ID}" \ NAME="${CONTAINER_NAME}" \ FRIENDLY_NAME="${CONTAINER_FRIENDLY_NAME}" \ VERSION="${CONTAINER_ARTIFACT_VERSION}" \ @@ -69,7 +68,7 @@ do_image_container_artifacts() { LABELS_JSON="${CONTAINER_ARTIFACT_LABELS_JSON}" \ python3 -c 'import json, os, sys; \ parse_bool = lambda name: os.environ[name].strip().lower() == "true"; \ -payload = {"package_id": os.environ["PACKAGE_ID"], "name": os.environ["NAME"], "friendly_name": os.environ["FRIENDLY_NAME"], "version": os.environ["VERSION"], "runtime": os.environ["RUNTIME"], "registration_defaults": {"autostart": parse_bool("AUTOSTART"), "monitor": parse_bool("MONITOR"), "drm": {"enabled": parse_bool("DRM_ENABLED"), "stats_sample_interval_s": int(os.environ["DRM_STATS_SAMPLE_INTERVAL"]), "stats_list_of_metrics": json.loads(os.environ["DRM_STATS_LIST_OF_METRICS"])}, "restart": {"enabled": parse_bool("RESTART_ENABLED"), "max_retries": int(os.environ["RESTART_MAX_RETRIES"]), "window": int(os.environ["RESTART_WINDOW"]), "retry_delay": int(os.environ["RESTART_RETRY_DELAY"]) } }, "device_types": json.loads(os.environ["DEVICE_TYPES_JSON"]), "firmware_versions": os.environ["FIRMWARE_VERSIONS"], "build_id": os.environ["BUILD_ID"], "description": os.environ["DESCRIPTION"], "labels": json.loads(os.environ["LABELS_JSON"])}; \ +payload = {"name": os.environ["NAME"], "friendly_name": os.environ["FRIENDLY_NAME"], "version": os.environ["VERSION"], "runtime": os.environ["RUNTIME"], "registration_defaults": {"autostart": parse_bool("AUTOSTART"), "monitor": parse_bool("MONITOR"), "drm": {"enabled": parse_bool("DRM_ENABLED"), "stats_sample_interval_s": int(os.environ["DRM_STATS_SAMPLE_INTERVAL"]), "stats_list_of_metrics": json.loads(os.environ["DRM_STATS_LIST_OF_METRICS"])}, "restart": {"enabled": parse_bool("RESTART_ENABLED"), "max_retries": int(os.environ["RESTART_MAX_RETRIES"]), "window": int(os.environ["RESTART_WINDOW"]), "retry_delay": int(os.environ["RESTART_RETRY_DELAY"]) } }, "device_types": json.loads(os.environ["DEVICE_TYPES_JSON"]), "firmware_versions": os.environ["FIRMWARE_VERSIONS"], "build_id": os.environ["BUILD_ID"], "description": os.environ["DESCRIPTION"], "labels": json.loads(os.environ["LABELS_JSON"])}; \ create_args = os.environ["CREATE_ARGS"].strip(); \ payload.update({"create_args": create_args} if create_args else {}); \ open(sys.argv[1], "w", encoding="utf-8").write(json.dumps(payload, indent=2) + "\n")' \ diff --git a/meta-digi-containers/recipes-core/images/dey-image-container.bb b/meta-digi-containers/recipes-core/images/dey-image-container.bb index e10e19b59..919174a0f 100644 --- a/meta-digi-containers/recipes-core/images/dey-image-container.bb +++ b/meta-digi-containers/recipes-core/images/dey-image-container.bb @@ -57,7 +57,6 @@ LXC_CONFIG_FILE ?= "${LXC_CONFIG_DIR}/config_lxc_${MACHINE}" CONTAINER_ARTIFACT_TEMPLATE_DIR ?= "" CONTAINER_DEFAULT_ARTIFACT_TEMPLATE_DIR ?= "${CONTAINER_PROFILE_DIR}/artifact" META_DIGI_REPO_DIR ?= "${THISDIR}/../../.." -CONTAINER_PACKAGE_ID ?= "${CONTAINER_NAME}" CONTAINER_FRIENDLY_NAME ?= "${CONTAINER_NAME}" CONTAINER_ARTIFACT_VERSION ?= "${PV}" CONTAINER_CREATE_ARGS ?= "" diff --git a/meta-digi-containers/scripts/generate-dcp.py b/meta-digi-containers/scripts/generate-dcp.py index 327ee6df8..4868db40d 100755 --- a/meta-digi-containers/scripts/generate-dcp.py +++ b/meta-digi-containers/scripts/generate-dcp.py @@ -48,8 +48,8 @@ def format_created_at(timestamp: datetime) -> str: return timestamp.astimezone(timezone.utc).isoformat(timespec="milliseconds").replace("+00:00", "Z") -def build_generated_package_id(base_package_id: str, *, created_at_ms: int) -> str: - return f"{base_package_id}-{to_base36(created_at_ms)}" +def build_generated_package_id(base_name: str, *, created_at_ms: int) -> str: + return f"{base_name}-{to_base36(created_at_ms)}" def load_manifest(path: Path) -> dict: @@ -139,7 +139,11 @@ def normalize_drm_stats_metrics(metrics: list[str]) -> list[str]: def validate_manifest(data: dict) -> dict: - package_id = validate_string(data, "package_id", path="manifest") + package_id = data.get("package_id") + if package_id is not None: + if not isinstance(package_id, str) or not package_id.strip(): + fail("invalid manifest: package_id must be a non-empty string") + package_id = package_id.strip() version = validate_string(data, "version", path="manifest") runtime = validate_string(data, "runtime", path="manifest") if runtime not in {"lxc", "podman"}: @@ -175,11 +179,7 @@ def validate_manifest(data: dict) -> dict: description = data.get("description", "") if description is not None and not isinstance(description, str): fail("invalid manifest: description must be a string") - name = data.get("name") - if name is not None: - if not isinstance(name, str) or not name.strip(): - fail("invalid manifest: name must be a non-empty string") - name = name.strip() + name = validate_string(data, "name", path="manifest") friendly_name = data.get("friendly_name") if friendly_name is not None: if not isinstance(friendly_name, str) or not friendly_name.strip(): @@ -394,9 +394,13 @@ def main() -> int: created_at_dt = datetime.now(timezone.utc) created_at_ms = int(created_at_dt.timestamp() * 1000) created_at = format_created_at(created_at_dt) - generated_package_id = build_generated_package_id( - manifest["package_id"], - created_at_ms=created_at_ms, + generated_package_id = ( + manifest["package_id"] + if manifest["package_id"] + else build_generated_package_id( + manifest["name"], + created_at_ms=created_at_ms, + ) ) output_name = build_output_name( package_id=generated_package_id,