nemo_gym.sandbox.compose_fields
nemo_gym.sandbox.compose_fields
What a Compose service may say, and the shape each field takes before the adapter reads it.
The field allow-list of the sandbox Compose adapter and its message per offending key, the normalisation of deploy resources, devices and gpus, restart, pull_policy, platform, extra_hosts, hooks, networks and the provider service options, and check_compose_fields, which runs them all over a document and is a fixed point of its own output. The two Compose scalar and environment shape helpers, the memory size parser and the interpolation error class live here because the field checks, the resolver and the interpolation code in nemo_gym.data.tasks.harbor.compose_variables all read them, and this module sits below both. Nothing here reads a task or a record.
Module Contents
Classes
Functions
Data
API
Bases: ValueError
A Compose service field prepare cannot run as written; field is the Compose key it names.
Bases: ValueError
A Compose file names a variable or an env_file that prepare cannot resolve.
Bases: ComposeFieldError
A key the sandbox Compose adapter does not start at all (unsupported_compose_fields), as opposed to a
supported field written in a way the group cannot run.
An environment value as Compose would emit it: booleans lower-case, None empty.
GPUs requested by deploy.resources.reservations.devices: every entry must ask for the gpu
capability with a numeric count or explicit device_ids; count: all has no meaning in a pod.
A service’s environment as a mapping. A bare NAME in the list form, or a null value in the mapping
form, stands for the task variable of that name and is None when there is none: Compose then leaves the
variable unset in the container, even where an env_file sets it. NAME= and NAME: '' are empty.
A service’s networks as a mapping of network name to options; each must be declared (default is
implicit). Only aliases has a meaning; static addresses and the rest raise.
(field, message) per offending key of document, in document order: the top level first, then each
service; field is the first unknown key of that level. Only mappings are inspected: a document or service
that is not one fails the adapter’s shape checks instead.
Give every M28 service field its defined meaning, or raise ComposeFieldError naming the field.
The one field check: prepare runs it per task (nemo_gym.data.tasks.harbor.image_configs.check_task_compose_fields)
and the adapter again at start. A key outside the allow-list (unsupported_compose_fields: a sidecar
build:, privileged, logging, …) is an UnsupportedComposeFieldError before any value is
read. Mutates and returns document, and applied to its own output returns it unchanged: the server normalizes
once and the adapter again, from the written file. deploy is normalized (see normalize_deploy);
restart is validated and kept (recorded by the adapter, the group restarts nothing); pull_policy
becomes always, missing or never; platform must match platform, the one the deployment
runs (see deployment_platform); networks (top level and per service) and extra_hosts take
their mapping forms; post_start hooks are checked; ports take their long syntax, with the group’s
endpoint rules applied (see normalize_ports); tmpfs, ulimits, sysctls and
security_opt are normalized and, when provider is given, each must be in service_option_fields
(the provider’s SERVICE_OPTION_FIELDS) or the error names the field and the provider. A sidecar that
reserves GPUs through deploy.resources is checked against gpu_provider and
gpu_service_option_fields instead when gpu_provider is given, since that is the provider it runs on
(main follows the task, not its deploy block). Without a provider name the capability check is left
to the adapter, which runs it against the live provider of each service before any sandbox.
A service’s deploy block in the form the adapter reads.
resources.limits and resources.reservations carry cpus (a number) and memory (bytes);
reservations.devices becomes gpus, the GPU count. replicas must be 1. restart_policy
is kept as written and recorded, like restart. limits.pids and every other key name swarm
scheduling and raise ComposeFieldError.
extra_hosts as a hostname-to-address mapping, from the list (host:ip, host=ip) or mapping form.
host-gateway has no meaning in a pod and raises.
post_start entries as command (a string, run through the shell, or an argv list), optional user
(a name, or a numeric id as an integer), working_dir and environment (a mapping). privileged raises:
no hook escalates.
Top-level networks in the shape the adapter reads; every one maps onto the group’s single pod network.
name, driver, external, attachable and labels are accepted and have no further meaning:
services sharing a network reach each other by name, as on any Compose network. internal: true, ipam
with a configuration, driver_opts and enable_ipv6: true ask for isolation or addressing the pod does
not provide and raise ComposeFieldError naming them. Compose’s defaults spelled out (internal: false, enable_ipv6: false, an empty ipam block) ask for nothing and are dropped.
os/arch[/variant] as os/arch with Docker’s architecture aliases folded (x86_64 is amd64).
A service’s ports in long syntax, each entry checked the way the sandbox group runs it.
A short entry ("8080", "8080:80", "127.0.0.1:8080:80/udp", a bare integer) takes the mapping Compose
gives it (target, and published, host_ip, protocol when written), so prepare and the adapter
read one shape. The group exposes a service’s ports as endpoints the provider allocates, so a fixed
published port (anything but none or 0), a host_ip, a protocol other than TCP, a mode other than
ingress, a port range and an unknown option raise ComposeFieldError naming the service: the
refusals the adapter makes at seed, made at prepare, for the short and the long syntax alike.
Compose pull_policy as always, missing or never.
if_not_present is missing; the age forms daily, weekly and every_<duration> are also
missing, because a sandbox group holds no pull history. build raises: services do not build.
tmpfs, ulimits, sysctls and security_opt in one shape each: a list of mounts, a mapping of
name to an integer or {soft, hard}, a mapping of key to string, and a list of options.
GPUs a service requests through deploy.resources.reservations.devices (0 when none).
Read from the normalized reservations.gpus alone: the field check calls this on every sidecar before
resolve_compose has converted the legacy mem_limit/shm_size strings, so a CPU-only service
with mem_limit: 512M must not be sized here.
The sandbox resources a normalized service asks for: cpu, memory_mib and gpu when set.
deploy.resources.limits wins, then reservations, then the legacy cpus/mem_limit keys.
GPUs come from reservations.devices only, as Compose defines them.
The refusals the sandbox Compose adapter raises for the keys of document: one message per offender in
document order (the top level first, then each service), empty when every key is one the adapter starts.
The key allow-list is the first step of check_compose_fields, the one field check prepare and the
adapter run (a refused key is an UnsupportedComposeFieldError there). Pure and key-only, so prepare
also screens the raw file of a task about to be built with it (nemo_gym.data.tasks.harbor.prepare), before
interpolation gives the values their shapes.