Source code for deploy_tools.models.apptainer_app

from typing import Annotated, Literal

from pydantic import AnyUrl, Field, StringConstraints, UrlConstraints

from .app import ENTRYPOINT_NAME_REGEX
from .parent import ParentModel

MOUNT_PATH_REGEX = r"/[^:]*"  # Colon is excluded in short-form apptainer mounts
MOUNT_REGEX = rf"^{MOUNT_PATH_REGEX}(:{MOUNT_PATH_REGEX}(:(ro|rw))?)?$"
IMAGE_VERSION_REGEX = r"^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$"  # OCI specification

type MountPoint = Annotated[str, StringConstraints(pattern=MOUNT_REGEX)]


[docs] class EntrypointOptions(ParentModel): """Options applied when running an Apptainer entrypoint.""" apptainer_args: Annotated[ str, Field(description="Apptainer arguments to pass when launching the container"), ] = "" command_args: Annotated[ str, Field(description="Arguments to pass to command entrypoint") ] = "" mounts: Annotated[ list[MountPoint], Field( description="A list of mount points to add to the container in the form of " "'host_path[:container_path[:opts]]' where opts (mount options) can be " "'ro' or 'rw' and defaults to 'rw'" ), ] = [] host_binaries: Annotated[ list[str], Field( description="A list of host binaries to mount into the container. " "These are discovered on the host using the current PATH and are " "mounted into the container at /usr/bin/[binary_name]" ), ] = []
[docs] class Entrypoint(ParentModel): """Represents an entrypoint to a command on the Apptainer image. If no command is provided, the entrypoint (``name``) is used by default. This corresponds to the name of the executable provided by the Module. """ name: Annotated[ str, StringConstraints(pattern=ENTRYPOINT_NAME_REGEX), Field( description="Name of executable to use after loading the Module. Must " "start with a letter or underscore and contain only letters, digits, " "hyphens or underscores." ), ] command: Annotated[ str | None, Field(description="Command to run in container. Defaults to `name`"), ] = None options: Annotated[ EntrypointOptions, Field(description="Options to apply for this entrypoint") ] = EntrypointOptions()
[docs] class ContainerImage(ParentModel): """Reference to a container image, split into a base path and version/tag.""" path: Annotated[ AnyUrl, UrlConstraints(allowed_schemes=["docker", "shub", "oras", "https"]), Field( description="Image URL excluding the version/tag. Must be a valid URL as " "described here: " "https://apptainer.org/docs/user/main/cli/apptainer_pull.html#synopsis" ), ] version: Annotated[ str, StringConstraints(pattern=IMAGE_VERSION_REGEX), Field( description="Version or tag of the docker image. Must follow the OCI tag " "format: start with a letter, digit or underscore, followed by up to 127 " "letters, digits, full stops, hyphens or underscores." ), ] @property def url(self) -> str: """Full image reference combining the path and version as ``path:version``.""" return f"{self.path}:{self.version}"
[docs] class ApptainerApp(ParentModel): """Represents an Apptainer application or set of applications using a single image. This uses Apptainer to deploy a portable image of the desired container. Multiple entrypoints can be specified to allow different commands to be run on the same container image. """ app_type: Annotated[ Literal["apptainer"], Field( description="An Apptainer (executable container image) with multiple " "potential entrypoints" ), ] container: Annotated[ContainerImage, Field(description="Container URL information")] entrypoints: Annotated[ list[Entrypoint], Field(description="List of executables to run using the Apptainer"), ] global_options: Annotated[ EntrypointOptions, Field(description="Global options that apply to all Entrypoints"), ] = EntrypointOptions()