containers: derive DCP package id from logical name
Generate the package if from logical name when it is not specified in the json. If case it is set, use it. Signed-off-by: Isaac Hermida <isaac.hermida@digi.com>
This commit is contained in:
parent
3b93a2c2e1
commit
267f78ac9d
|
|
@ -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:
|
||||
- `<generated_package_id>_artifact_<runtime>_<device_types[0]>.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}-<base36_created_at_ms>_artifact_podman_<device_types[0]>.tar.gz`
|
||||
- `${CONTAINER_PACKAGE_ID}-<base36_created_at_ms>_artifact_lxc_<device_types[0]>.tar.gz`
|
||||
- `${CONTAINER_NAME}-<base36_created_at_ms>_artifact_podman_<device_types[0]>.tar.gz`
|
||||
- `${CONTAINER_NAME}-<base36_created_at_ms>_artifact_lxc_<device_types[0]>.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`
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"package_id": "flutter-demo",
|
||||
"name": "flutter-demo",
|
||||
"friendly_name": "Flutter Demo",
|
||||
"version": "1.0",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"package_id": "flutter-demo",
|
||||
"name": "flutter-demo",
|
||||
"friendly_name": "Flutter Demo",
|
||||
"version": "1.0",
|
||||
|
|
|
|||
|
|
@ -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")' \
|
||||
|
|
|
|||
|
|
@ -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 ?= ""
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue