feat(lab): bind sealed component adapter images
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
FROM ndc/mission-core-lab-v1-goose:sg3.2.0-cu117-v1
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
WORKDIR /opt/nodedc/adapter
|
||||||
|
|
||||||
|
ARG NODEDC_SHARED_ADAPTER_SHA256
|
||||||
|
ARG NODEDC_COMPONENT_ADAPTER_SHA256
|
||||||
|
|
||||||
|
COPY portable_lab_v1_component_adapter.py ./portable_lab_v1_component_adapter.py
|
||||||
|
COPY run_portable_lab_v1_ddrnet_component.py ./run_portable_lab_v1_ddrnet_component.py
|
||||||
|
|
||||||
|
RUN test "$(sha256sum portable_lab_v1_component_adapter.py | cut -d' ' -f1)" = \
|
||||||
|
"${NODEDC_SHARED_ADAPTER_SHA256}" \
|
||||||
|
&& test "$(sha256sum run_portable_lab_v1_ddrnet_component.py | cut -d' ' -f1)" = \
|
||||||
|
"${NODEDC_COMPONENT_ADAPTER_SHA256}" \
|
||||||
|
&& chmod 0444 portable_lab_v1_component_adapter.py \
|
||||||
|
run_portable_lab_v1_ddrnet_component.py \
|
||||||
|
&& conda run --no-capture-output --name goose python -B -m py_compile \
|
||||||
|
portable_lab_v1_component_adapter.py \
|
||||||
|
run_portable_lab_v1_ddrnet_component.py \
|
||||||
|
&& rm -rf __pycache__
|
||||||
|
|
||||||
|
LABEL org.opencontainers.image.title="NODE.DC LAB V1 DDRNet adapter" \
|
||||||
|
com.nodedc.product="mission-core" \
|
||||||
|
com.nodedc.stack="observatory" \
|
||||||
|
com.nodedc.component="lab-v1-ddrnet" \
|
||||||
|
com.nodedc.authority="observation-only" \
|
||||||
|
com.nodedc.base-image.sha256="591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd" \
|
||||||
|
com.nodedc.shared-adapter.sha256="${NODEDC_SHARED_ADAPTER_SHA256}" \
|
||||||
|
com.nodedc.component-adapter.sha256="${NODEDC_COMPONENT_ADAPTER_SHA256}"
|
||||||
|
|
||||||
|
ENTRYPOINT ["conda", "run", "--no-capture-output", "--name", "goose", "python"]
|
||||||
|
CMD ["/opt/nodedc/adapter/run_portable_lab_v1_ddrnet_component.py"]
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
FROM nvcr.io/nvidia/tritonserver:26.06-py3@sha256:58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794
|
||||||
|
|
||||||
|
ENV HF_HUB_OFFLINE=1 \
|
||||||
|
TRANSFORMERS_OFFLINE=1 \
|
||||||
|
PYTHONNOUSERSITE=1 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
WORKDIR /opt/nodedc/adapter
|
||||||
|
|
||||||
|
ARG NODEDC_SHARED_ADAPTER_SHA256
|
||||||
|
ARG NODEDC_COMPONENT_ADAPTER_SHA256
|
||||||
|
|
||||||
|
COPY portable_lab_v1_component_adapter.py ./portable_lab_v1_component_adapter.py
|
||||||
|
COPY run_portable_lab_v1_eomt_component.py ./run_portable_lab_v1_eomt_component.py
|
||||||
|
|
||||||
|
RUN test "$(sha256sum portable_lab_v1_component_adapter.py | cut -d' ' -f1)" = \
|
||||||
|
"${NODEDC_SHARED_ADAPTER_SHA256}" \
|
||||||
|
&& test "$(sha256sum run_portable_lab_v1_eomt_component.py | cut -d' ' -f1)" = \
|
||||||
|
"${NODEDC_COMPONENT_ADAPTER_SHA256}" \
|
||||||
|
&& chmod 0444 portable_lab_v1_component_adapter.py \
|
||||||
|
run_portable_lab_v1_eomt_component.py \
|
||||||
|
&& python3 -B -m py_compile portable_lab_v1_component_adapter.py \
|
||||||
|
run_portable_lab_v1_eomt_component.py \
|
||||||
|
&& rm -rf __pycache__
|
||||||
|
|
||||||
|
LABEL org.opencontainers.image.title="NODE.DC LAB V1 EoMT adapter" \
|
||||||
|
com.nodedc.product="mission-core" \
|
||||||
|
com.nodedc.stack="observatory" \
|
||||||
|
com.nodedc.component="lab-v1-eomt" \
|
||||||
|
com.nodedc.authority="observation-only" \
|
||||||
|
com.nodedc.base-image.sha256="58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794" \
|
||||||
|
com.nodedc.shared-adapter.sha256="${NODEDC_SHARED_ADAPTER_SHA256}" \
|
||||||
|
com.nodedc.component-adapter.sha256="${NODEDC_COMPONENT_ADAPTER_SHA256}"
|
||||||
|
|
||||||
|
ENTRYPOINT ["python3"]
|
||||||
|
CMD ["/opt/nodedc/adapter/run_portable_lab_v1_eomt_component.py"]
|
||||||
@@ -59,8 +59,6 @@ PORTABLE_LAB_V1_COMPONENT_INSTALLATION_SCHEMA: Final = (
|
|||||||
_SETUP_ID: Final = "lab-v1-eomt-ddrnet-portable-v1"
|
_SETUP_ID: Final = "lab-v1-eomt-ddrnet-portable-v1"
|
||||||
_DEFINITION_ID: Final = "lab-v1-eomt-ddrnet-portable"
|
_DEFINITION_ID: Final = "lab-v1-eomt-ddrnet-portable"
|
||||||
_DEFINITION_VERSION: Final = 2
|
_DEFINITION_VERSION: Final = 2
|
||||||
_EOMT_IMAGE_SHA256: Final = "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794"
|
|
||||||
_DDRNET_IMAGE_SHA256: Final = "591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd"
|
|
||||||
_EOMT_PIPELINE: Final = "recorded-semantic-eomt-fisheye-mask/v1"
|
_EOMT_PIPELINE: Final = "recorded-semantic-eomt-fisheye-mask/v1"
|
||||||
_DDRNET_CHECKPOINT_SHA256: Final = (
|
_DDRNET_CHECKPOINT_SHA256: Final = (
|
||||||
"b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6"
|
"b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6"
|
||||||
@@ -80,54 +78,56 @@ type PortableLabV1Component = Literal["eomt", "ddrnet"]
|
|||||||
type PortableLabV1AssetKind = Literal["file", "tree"]
|
type PortableLabV1AssetKind = Literal["file", "tree"]
|
||||||
type PortableLabV1AssetVerification = Literal["sha256", "identity-sha256"]
|
type PortableLabV1AssetVerification = Literal["sha256", "identity-sha256"]
|
||||||
|
|
||||||
_EXPECTED_ASSET_IDENTITIES: Final[dict[PortableLabV1Component, dict[str, str]]] = {
|
_EXPECTED_ASSET_TARGETS: Final[dict[PortableLabV1Component, dict[str, str]]] = {
|
||||||
"eomt": {
|
"eomt": {
|
||||||
"eomt-config-json": ("7f4aa94fa4e43c0dbd79a5420edb511120aef62bd82bfbcbcece79948286a650"),
|
"eomt-environment": "/environment",
|
||||||
"eomt-dependency-set": ("4eb1f8d33236806e74f9e5bb96b7dce2ac37623dc39b2184be2aa8d7d00e983e"),
|
"eomt-ffmpeg-runtime": "/opt/ffmpeg",
|
||||||
"eomt-evaluation-helper": (
|
"eomt-model-cache": "/cache",
|
||||||
"25baf30c0df564734e08f38ace88cc4bc147cacf240c761622279511e361daa4"
|
"eomt-python-environment": "/opt/env",
|
||||||
),
|
"eomt-runner-bundle": "/runner",
|
||||||
"eomt-model-weights": ("c265da9a74f58f5c3f4826d23ca4ca78beac0b106cca5842beca61580de5b782"),
|
"eomt-transformers-environment": "/opt/transformers",
|
||||||
"eomt-preprocessor-config": (
|
"k1-valid-fov-root": "/valid-fov",
|
||||||
"97e2fbf7f0bdba2cfc90251c5133bae9c27ddc9c4410509f40670be2332854e7"
|
|
||||||
),
|
|
||||||
"eomt-profile": ("ea583966bc3409f5cf563cbf4fad05e366907e67187082eb692aff53d9f5d875"),
|
|
||||||
"eomt-profile-runtime": (
|
|
||||||
"01881862d4eaa218955f776a948124bf19c34be2b5ec282115daeacb15c53ae6"
|
|
||||||
),
|
|
||||||
"eomt-recorded-runtime": (
|
|
||||||
"4dcc4fc8bdf33702651a199be69d0dd4fadb243d2e65aee1c3d1ae7a58fdf675"
|
|
||||||
),
|
|
||||||
"eomt-runner": ("651e8e06c3912dffb036b7fd08f2c0623f7563d8306cc7aee05db562798518f4"),
|
|
||||||
"k1-valid-fov-identity": (
|
|
||||||
"b4dd8ddf2b87c1d520ee8a0868c4fea062d7c14d1bae73ccabd3abe1f3acbac2"
|
|
||||||
),
|
|
||||||
"k1-valid-fov-mask": ("a40cee06b7c6f69b6a09a11563dcfd237f3de833b1ccd31459e66692e528ba63"),
|
|
||||||
},
|
},
|
||||||
"ddrnet": {
|
"ddrnet": {
|
||||||
|
"ddrnet-checkpoint": "/opt/nodedc/assets/ddrnet-checkpoint",
|
||||||
|
"ddrnet-goose-mapping": "/opt/nodedc/assets/ddrnet-goose-mapping",
|
||||||
|
"ddrnet-goose-runner": "/opt/nodedc/assets/ddrnet-goose-runner",
|
||||||
|
"vegetation-policy": "/opt/nodedc/assets/vegetation-policy",
|
||||||
|
"vegetation-provider-map": "/opt/nodedc/assets/vegetation-provider-map",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_EXPECTED_FIXED_ASSET_IDENTITIES: Final[dict[str, str]] = {
|
||||||
|
"eomt-ffmpeg-runtime": "03651449fdcccec847a0f1241e1663a82cf374bd94e7470b4ddb0c0e46d88c69",
|
||||||
"ddrnet-checkpoint": _DDRNET_CHECKPOINT_SHA256,
|
"ddrnet-checkpoint": _DDRNET_CHECKPOINT_SHA256,
|
||||||
"ddrnet-goose-mapping": _GOOSE_MAPPING_SHA256,
|
"ddrnet-goose-mapping": _GOOSE_MAPPING_SHA256,
|
||||||
"ddrnet-goose-runner": ("b18ad60f277eea69a240a28f290611b94627fb9707faf1bb3e6e22102dad67c1"),
|
"ddrnet-goose-runner": "b18ad60f277eea69a240a28f290611b94627fb9707faf1bb3e6e22102dad67c1",
|
||||||
"vegetation-policy": ("b75c4ac841d7b4bcc57f7a9c8417ca2317d8ecfa499e72a9af8a8591a2ec0d35"),
|
"vegetation-policy": "b75c4ac841d7b4bcc57f7a9c8417ca2317d8ecfa499e72a9af8a8591a2ec0d35",
|
||||||
"vegetation-provider-map": (
|
"vegetation-provider-map": (
|
||||||
"f2b69046b6a740fd9532d2d88e7fabae7c20fb662f783c9502adc9026406f352"
|
"f2b69046b6a740fd9532d2d88e7fabae7c20fb662f783c9502adc9026406f352"
|
||||||
),
|
),
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_EXPECTED_ASSET_LENGTHS: Final[dict[str, int]] = {
|
_EXPECTED_ASSET_LENGTHS: Final[dict[str, int]] = {
|
||||||
|
"eomt-ffmpeg-runtime": 256_208_352,
|
||||||
"ddrnet-checkpoint": 259_419_077,
|
"ddrnet-checkpoint": 259_419_077,
|
||||||
"ddrnet-goose-runner": 32_877,
|
"ddrnet-goose-runner": 32_877,
|
||||||
"eomt-config-json": 1_575,
|
|
||||||
"eomt-evaluation-helper": 28_915,
|
|
||||||
"eomt-model-weights": 1_276_175_488,
|
|
||||||
"eomt-preprocessor-config": 666,
|
|
||||||
"eomt-profile": 3_805,
|
|
||||||
"eomt-profile-runtime": 45_789,
|
|
||||||
"eomt-recorded-runtime": 34_899,
|
|
||||||
"eomt-runner": 30_720,
|
|
||||||
"vegetation-policy": 3_022,
|
"vegetation-policy": 3_022,
|
||||||
"vegetation-provider-map": 2_756,
|
"vegetation-provider-map": 2_756,
|
||||||
}
|
}
|
||||||
|
_EXPECTED_ENTRYPOINTS: Final[dict[PortableLabV1Component, tuple[str, ...]]] = {
|
||||||
|
"eomt": ("python3",),
|
||||||
|
"ddrnet": (
|
||||||
|
"conda",
|
||||||
|
"run",
|
||||||
|
"--no-capture-output",
|
||||||
|
"--name",
|
||||||
|
"goose",
|
||||||
|
"python",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
_EXPECTED_COMMANDS: Final[dict[PortableLabV1Component, tuple[str, ...]]] = {
|
||||||
|
"eomt": ("/opt/nodedc/adapter/run_portable_lab_v1_eomt_component.py",),
|
||||||
|
"ddrnet": ("/opt/nodedc/adapter/run_portable_lab_v1_ddrnet_component.py",),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class PortableLabV1LocalRunnerError(PortableLabV1WorkerError):
|
class PortableLabV1LocalRunnerError(PortableLabV1WorkerError):
|
||||||
@@ -154,8 +154,18 @@ class PortableLabV1HostAsset:
|
|||||||
_safe_token(self.asset_id, "asset id")
|
_safe_token(self.asset_id, "asset id")
|
||||||
_host_path(self.host_path, "asset host path")
|
_host_path(self.host_path, "asset host path")
|
||||||
target = _container_path(self.container_path, "asset container path")
|
target = _container_path(self.container_path, "asset container path")
|
||||||
if target.parts[:4] != ("/", "opt", "nodedc", "assets"):
|
expected_target = next(
|
||||||
raise PortableLabV1LocalRunnerError("asset target is outside /opt/nodedc/assets")
|
(
|
||||||
|
paths[self.asset_id]
|
||||||
|
for paths in _EXPECTED_ASSET_TARGETS.values()
|
||||||
|
if self.asset_id in paths
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if expected_target is None or target.as_posix() != expected_target:
|
||||||
|
raise PortableLabV1LocalRunnerError(
|
||||||
|
"asset target differs from its fixed component path"
|
||||||
|
)
|
||||||
_digest(self.identity_sha256, "asset identity sha256")
|
_digest(self.identity_sha256, "asset identity sha256")
|
||||||
if self.kind == "file" and self.verification != "sha256":
|
if self.kind == "file" and self.verification != "sha256":
|
||||||
raise PortableLabV1LocalRunnerError(
|
raise PortableLabV1LocalRunnerError(
|
||||||
@@ -210,11 +220,15 @@ class PortableLabV1ComponentInstallation:
|
|||||||
if self.component not in ("eomt", "ddrnet"):
|
if self.component not in ("eomt", "ddrnet"):
|
||||||
raise PortableLabV1LocalRunnerError("component identity is invalid")
|
raise PortableLabV1LocalRunnerError("component identity is invalid")
|
||||||
_digest(self.image_sha256, "component image sha256")
|
_digest(self.image_sha256, "component image sha256")
|
||||||
expected_image = _EOMT_IMAGE_SHA256 if self.component == "eomt" else _DDRNET_IMAGE_SHA256
|
|
||||||
if self.image_sha256 != expected_image:
|
|
||||||
raise PortableLabV1LocalRunnerError(f"{self.component} image identity changed")
|
|
||||||
_argv(self.entrypoint, "component entrypoint")
|
_argv(self.entrypoint, "component entrypoint")
|
||||||
_argv(self.command, "component command")
|
_argv(self.command, "component command")
|
||||||
|
if (
|
||||||
|
self.entrypoint != _EXPECTED_ENTRYPOINTS[self.component]
|
||||||
|
or self.command != _EXPECTED_COMMANDS[self.component]
|
||||||
|
):
|
||||||
|
raise PortableLabV1LocalRunnerError(
|
||||||
|
f"{self.component} adapter entrypoint changed"
|
||||||
|
)
|
||||||
if not (1.0 <= self.timeout_seconds <= 24 * 60 * 60):
|
if not (1.0 <= self.timeout_seconds <= 24 * 60 * 60):
|
||||||
raise PortableLabV1LocalRunnerError("component timeout is invalid")
|
raise PortableLabV1LocalRunnerError("component timeout is invalid")
|
||||||
if not (1024**3 <= self.memory_bytes <= 128 * 1024**3):
|
if not (1024**3 <= self.memory_bytes <= 128 * 1024**3):
|
||||||
@@ -227,10 +241,31 @@ class PortableLabV1ComponentInstallation:
|
|||||||
targets = tuple(asset.container_path for asset in self.assets)
|
targets = tuple(asset.container_path for asset in self.assets)
|
||||||
if len(targets) != len(set(targets)):
|
if len(targets) != len(set(targets)):
|
||||||
raise PortableLabV1LocalRunnerError("component asset targets overlap")
|
raise PortableLabV1LocalRunnerError("component asset targets overlap")
|
||||||
expected = _EXPECTED_ASSET_IDENTITIES[self.component]
|
expected = _EXPECTED_ASSET_TARGETS[self.component]
|
||||||
if set(asset_ids) != set(expected):
|
if set(asset_ids) != set(expected):
|
||||||
raise PortableLabV1LocalRunnerError(f"{self.component} installed asset set changed")
|
raise PortableLabV1LocalRunnerError(f"{self.component} installed asset set changed")
|
||||||
if any(asset.identity_sha256 != expected[asset.asset_id] for asset in self.assets):
|
if any(asset.container_path != expected[asset.asset_id] for asset in self.assets):
|
||||||
|
raise PortableLabV1LocalRunnerError(
|
||||||
|
f"{self.component} installed asset target changed"
|
||||||
|
)
|
||||||
|
expected_kind: PortableLabV1AssetKind = (
|
||||||
|
"tree" if self.component == "eomt" else "file"
|
||||||
|
)
|
||||||
|
expected_verification: PortableLabV1AssetVerification = (
|
||||||
|
"identity-sha256" if self.component == "eomt" else "sha256"
|
||||||
|
)
|
||||||
|
if any(
|
||||||
|
asset.kind != expected_kind or asset.verification != expected_verification
|
||||||
|
for asset in self.assets
|
||||||
|
):
|
||||||
|
raise PortableLabV1LocalRunnerError(
|
||||||
|
f"{self.component} installed asset verification changed"
|
||||||
|
)
|
||||||
|
if any(
|
||||||
|
asset.asset_id in _EXPECTED_FIXED_ASSET_IDENTITIES
|
||||||
|
and asset.identity_sha256 != _EXPECTED_FIXED_ASSET_IDENTITIES[asset.asset_id]
|
||||||
|
for asset in self.assets
|
||||||
|
):
|
||||||
raise PortableLabV1LocalRunnerError(
|
raise PortableLabV1LocalRunnerError(
|
||||||
f"{self.component} installed asset identity changed"
|
f"{self.component} installed asset identity changed"
|
||||||
)
|
)
|
||||||
@@ -440,11 +475,14 @@ class PortableLabV1DockerLaunch:
|
|||||||
if self.component not in ("eomt", "ddrnet"):
|
if self.component not in ("eomt", "ddrnet"):
|
||||||
raise PortableLabV1LocalRunnerError("launch component is invalid")
|
raise PortableLabV1LocalRunnerError("launch component is invalid")
|
||||||
_digest(self.image_sha256, "launch image sha256")
|
_digest(self.image_sha256, "launch image sha256")
|
||||||
expected_image = _EOMT_IMAGE_SHA256 if self.component == "eomt" else _DDRNET_IMAGE_SHA256
|
|
||||||
if self.image_sha256 != expected_image:
|
|
||||||
raise PortableLabV1LocalRunnerError("launch image identity changed")
|
|
||||||
_argv(self.entrypoint, "launch entrypoint")
|
_argv(self.entrypoint, "launch entrypoint")
|
||||||
_argv(self.command, "launch command")
|
_argv(self.command, "launch command")
|
||||||
|
if (
|
||||||
|
self.entrypoint != _EXPECTED_ENTRYPOINTS[self.component]
|
||||||
|
or self.command[:-2] != _EXPECTED_COMMANDS[self.component]
|
||||||
|
or self.command[-2:] != ("--request", "/run/nodedc/request.json")
|
||||||
|
):
|
||||||
|
raise PortableLabV1LocalRunnerError("launch adapter command changed")
|
||||||
_safe_token(self.name_token, "launch name token")
|
_safe_token(self.name_token, "launch name token")
|
||||||
if not (1.0 <= self.timeout_seconds <= 24 * 60 * 60):
|
if not (1.0 <= self.timeout_seconds <= 24 * 60 * 60):
|
||||||
raise PortableLabV1LocalRunnerError("launch timeout is invalid")
|
raise PortableLabV1LocalRunnerError("launch timeout is invalid")
|
||||||
@@ -458,10 +496,11 @@ class PortableLabV1DockerLaunch:
|
|||||||
writable = tuple(mount for mount in self.mounts if not mount.read_only)
|
writable = tuple(mount for mount in self.mounts if not mount.read_only)
|
||||||
if len(writable) != 1 or writable[0].container_path != "/run/nodedc/output":
|
if len(writable) != 1 or writable[0].container_path != "/run/nodedc/output":
|
||||||
raise PortableLabV1LocalRunnerError("Docker writable mount surface changed")
|
raise PortableLabV1LocalRunnerError("Docker writable mount surface changed")
|
||||||
|
allowed_asset_targets = set(_EXPECTED_ASSET_TARGETS[self.component].values())
|
||||||
if any(
|
if any(
|
||||||
not (
|
not (
|
||||||
mount.container_path.startswith("/run/nodedc/")
|
mount.container_path.startswith("/run/nodedc/")
|
||||||
or mount.container_path.startswith("/opt/nodedc/assets/")
|
or mount.container_path in allowed_asset_targets
|
||||||
)
|
)
|
||||||
for mount in self.mounts
|
for mount in self.mounts
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import hashlib
|
||||||
import json
|
import json
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -21,6 +22,7 @@ EOMT_IMAGE_SHA256 = "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf
|
|||||||
DDRNET_IMAGE_SHA256 = "591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd"
|
DDRNET_IMAGE_SHA256 = "591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd"
|
||||||
DEFINITION_SHA256 = "a" * 64
|
DEFINITION_SHA256 = "a" * 64
|
||||||
RELEASE_SHA256 = "b" * 64
|
RELEASE_SHA256 = "b" * 64
|
||||||
|
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -42,19 +44,21 @@ class _Plan:
|
|||||||
def _assets(
|
def _assets(
|
||||||
component: local_runners.PortableLabV1Component,
|
component: local_runners.PortableLabV1Component,
|
||||||
) -> tuple[local_runners.PortableLabV1HostAsset, ...]:
|
) -> tuple[local_runners.PortableLabV1HostAsset, ...]:
|
||||||
identities = local_runners._EXPECTED_ASSET_IDENTITIES[component]
|
targets = local_runners._EXPECTED_ASSET_TARGETS[component]
|
||||||
tree_assets = {"eomt-dependency-set", "k1-valid-fov-identity"}
|
|
||||||
return tuple(
|
return tuple(
|
||||||
local_runners.PortableLabV1HostAsset(
|
local_runners.PortableLabV1HostAsset(
|
||||||
asset_id=asset_id,
|
asset_id=asset_id,
|
||||||
host_path=f"D:\\NDC_MISSIONCORE\\assets\\{asset_id}",
|
host_path=f"D:\\NDC_MISSIONCORE\\assets\\{asset_id}",
|
||||||
container_path=f"/opt/nodedc/assets/{asset_id}",
|
container_path=container_path,
|
||||||
kind="tree" if asset_id in tree_assets else "file",
|
kind="tree" if component == "eomt" else "file",
|
||||||
verification=("identity-sha256" if asset_id in tree_assets else "sha256"),
|
verification=("identity-sha256" if component == "eomt" else "sha256"),
|
||||||
identity_sha256=identity,
|
identity_sha256=local_runners._EXPECTED_FIXED_ASSET_IDENTITIES.get(
|
||||||
byte_length=local_runners._EXPECTED_ASSET_LENGTHS.get(asset_id),
|
asset_id,
|
||||||
|
hashlib.sha256(asset_id.encode()).hexdigest(),
|
||||||
|
),
|
||||||
|
byte_length=local_runners._EXPECTED_ASSET_LENGTHS.get(asset_id, 1_024),
|
||||||
)
|
)
|
||||||
for asset_id, identity in sorted(identities.items())
|
for asset_id, container_path in sorted(targets.items())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -64,8 +68,8 @@ def _component(
|
|||||||
return local_runners.PortableLabV1ComponentInstallation.seal(
|
return local_runners.PortableLabV1ComponentInstallation.seal(
|
||||||
component=component,
|
component=component,
|
||||||
image_sha256=(EOMT_IMAGE_SHA256 if component == "eomt" else DDRNET_IMAGE_SHA256),
|
image_sha256=(EOMT_IMAGE_SHA256 if component == "eomt" else DDRNET_IMAGE_SHA256),
|
||||||
entrypoint=("/opt/nodedc/bin/portable-lab-v1-agent",),
|
entrypoint=local_runners._EXPECTED_ENTRYPOINTS[component],
|
||||||
command=(f"run-{component}",),
|
command=local_runners._EXPECTED_COMMANDS[component],
|
||||||
assets=_assets(component),
|
assets=_assets(component),
|
||||||
timeout_seconds=3600.0,
|
timeout_seconds=3600.0,
|
||||||
memory_bytes=16 * 1024**3,
|
memory_bytes=16 * 1024**3,
|
||||||
@@ -148,8 +152,12 @@ def _docker_launch(tmp_path: Path) -> local_runners.PortableLabV1DockerLaunch:
|
|||||||
return local_runners.PortableLabV1DockerLaunch(
|
return local_runners.PortableLabV1DockerLaunch(
|
||||||
component="eomt",
|
component="eomt",
|
||||||
image_sha256=EOMT_IMAGE_SHA256,
|
image_sha256=EOMT_IMAGE_SHA256,
|
||||||
entrypoint=("/opt/nodedc/bin/portable-lab-v1-agent",),
|
entrypoint=local_runners._EXPECTED_ENTRYPOINTS["eomt"],
|
||||||
command=("run-eomt", "--request", "/run/nodedc/request.json"),
|
command=(
|
||||||
|
"/opt/nodedc/adapter/run_portable_lab_v1_eomt_component.py",
|
||||||
|
"--request",
|
||||||
|
"/run/nodedc/request.json",
|
||||||
|
),
|
||||||
mounts=(
|
mounts=(
|
||||||
local_runners.PortableLabV1DockerMount(
|
local_runners.PortableLabV1DockerMount(
|
||||||
host_path="D:\\NDC_MISSIONCORE\\runtime\\output",
|
host_path="D:\\NDC_MISSIONCORE\\runtime\\output",
|
||||||
@@ -522,10 +530,37 @@ def test_component_installation_rejects_wrong_worker006_asset_identity() -> None
|
|||||||
local_runners.PortableLabV1ComponentInstallation.seal(
|
local_runners.PortableLabV1ComponentInstallation.seal(
|
||||||
component="ddrnet",
|
component="ddrnet",
|
||||||
image_sha256=DDRNET_IMAGE_SHA256,
|
image_sha256=DDRNET_IMAGE_SHA256,
|
||||||
entrypoint=("/opt/nodedc/bin/portable-lab-v1-agent",),
|
entrypoint=local_runners._EXPECTED_ENTRYPOINTS["ddrnet"],
|
||||||
command=("run-ddrnet",),
|
command=local_runners._EXPECTED_COMMANDS["ddrnet"],
|
||||||
assets=tuple(assets),
|
assets=tuple(assets),
|
||||||
timeout_seconds=3600.0,
|
timeout_seconds=3600.0,
|
||||||
memory_bytes=16 * 1024**3,
|
memory_bytes=16 * 1024**3,
|
||||||
nano_cpus=4_000_000_000,
|
nano_cpus=4_000_000_000,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_component_adapter_images_are_thin_offline_wrappers() -> None:
|
||||||
|
eomt = (
|
||||||
|
REPOSITORY_ROOT
|
||||||
|
/ "experiments/perception/worker/observatory_portable/"
|
||||||
|
"Dockerfile.lab-v1-eomt-adapter"
|
||||||
|
).read_text(encoding="utf-8")
|
||||||
|
ddrnet = (
|
||||||
|
REPOSITORY_ROOT
|
||||||
|
/ "experiments/perception/worker/observatory_portable/"
|
||||||
|
"Dockerfile.lab-v1-ddrnet-adapter"
|
||||||
|
).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert "FROM nvcr.io/nvidia/tritonserver:26.06-py3@sha256:" in eomt
|
||||||
|
assert "FROM ndc/mission-core-lab-v1-goose:sg3.2.0-cu117-v1" in ddrnet
|
||||||
|
assert "COPY portable_lab_v1_component_adapter.py" in eomt
|
||||||
|
assert "COPY portable_lab_v1_component_adapter.py" in ddrnet
|
||||||
|
assert 'ENTRYPOINT ["python3"]' in eomt
|
||||||
|
assert 'ENTRYPOINT ["conda", "run", "--no-capture-output"' in ddrnet
|
||||||
|
for dockerfile in (eomt, ddrnet):
|
||||||
|
assert "apt-get" not in dockerfile
|
||||||
|
assert "pip install" not in dockerfile
|
||||||
|
assert "curl " not in dockerfile
|
||||||
|
assert "wget " not in dockerfile
|
||||||
|
assert "NODEDC_SHARED_ADAPTER_SHA256" in dockerfile
|
||||||
|
assert "NODEDC_COMPONENT_ADAPTER_SHA256" in dockerfile
|
||||||
|
|||||||
Reference in New Issue
Block a user