# Copyright 2025 Alibaba Group Holding Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Pydantic schemas for OpenSandbox Lifecycle API. This module defines data models based on the OpenAPI specification for request/response validation and serialization. """ from datetime import datetime from typing import Dict, List, Literal, Optional from pydantic import BaseModel, Field, RootModel, model_validator # ============================================================================ # Image Specification # ============================================================================ class ImageAuth(BaseModel): """ Registry authentication credentials for private container registries. """ username: str = Field(..., description="Registry username or service account") password: str = Field(..., description="Registry password or authentication token") class ImageSpec(BaseModel): """ Container image specification for sandbox provisioning. Supports public registry images and private registry images with authentication. """ uri: str = Field( ..., description="Container image URI in standard format (e.g., 'python:3.11', 'gcr.io/my-project/app:v1.0')", ) auth: Optional[ImageAuth] = Field( None, description="Registry authentication credentials (required for private registries)", ) class PlatformSpec(BaseModel): """ Runtime platform constraint for scheduling/provisioning. """ os: str = Field( ..., description="Target operating system (for example 'linux').", ) arch: str = Field( ..., description="Target CPU architecture (for example 'amd64' or 'arm64').", ) # ============================================================================ # Resource Limits # ============================================================================ class ResourceLimits(RootModel[Dict[str, str]]): """ Runtime resource constraints as key-value pairs. Similar to Kubernetes resource specifications, allows flexible definition of resource limits. Common resource types include cpu, memory, and gpu. """ root: Dict[str, str] = Field( default_factory=dict, example={"cpu": "500m", "memory": "512Mi", "gpu": "1"}, ) class NetworkRule(BaseModel): """ Egress rule: allow/deny a specific domain or wildcard. """ action: str = Field(..., description="Whether to allow or deny matching targets (allow | deny).") target: str = Field( ..., description="FQDN or wildcard domain (e.g., 'example.com', '*.example.com').", min_length=1, ) class Config: populate_by_name = True class NetworkPolicy(BaseModel): """ Egress network policy matching the sidecar /policy payload. """ default_action: Optional[str] = Field( default=None, alias="defaultAction", description="Default action when no egress rule matches (allow | deny). If omitted, sidecar defaults to deny.", ) egress: list[NetworkRule] = Field( default_factory=list, description="Ordered egress rules. Empty/omitted yields allow-all at startup.", ) class Config: populate_by_name = True class CredentialProxyConfig(BaseModel): """ Credential proxy startup options. """ enabled: bool = Field( False, description=( "When true, the server enables transparent MITM support required by " "Credential Vault injection. Plain egress network policy does not enable " "transparent MITM unless this option is set." ), ) class Config: populate_by_name = True # ============================================================================ # Volume Definitions # ============================================================================ class Host(BaseModel): """ Host path bind mount backend. Maps a directory on the host filesystem into the container. Only available when the runtime supports host mounts. Security note: Host paths are restricted by server-side allowlist. Users must specify paths under permitted prefixes. """ path: str = Field( ..., description="Absolute path on the host filesystem to mount.", pattern=r"^(/|[A-Za-z]:[\\/])", ) class PVC(BaseModel): """ Platform-managed named volume backend. A runtime-neutral abstraction for referencing a platform-managed named volume. If ``createIfNotExists`` is true (the default) and the volume does not yet exist, it will be created automatically using the provisioning hints below. - Kubernetes: maps to a PersistentVolumeClaim in the same namespace. - Docker: maps to a Docker named volume (created via ``docker volume create``). """ claim_name: str = Field( ..., alias="claimName", description=( "Name of the volume on the target platform. " "In Kubernetes this is the PVC name; in Docker this is the named volume name." ), pattern=r"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$", max_length=253, ) create_if_not_exists: bool = Field( True, alias="createIfNotExists", description=( "When true, the volume is automatically created if it does not exist. " "When false, referencing a non-existent volume fails with an error." ), ) delete_on_sandbox_termination: bool = Field( False, alias="deleteOnSandboxTermination", description=( "When true, the volume is automatically removed when the sandbox is " "deleted. Only applies to volumes that were auto-created by the server " "on this request; pre-existing volumes are never removed. For " "Kubernetes, the resulting PVC delete then triggers the bound PV's " "StorageClass reclaim policy (Retain/Delete)." ), ) # Provisioning hints — used only when auto-creating a new volume. # Ignored if the volume already exists on the platform. storage_class: Optional[str] = Field( None, alias="storageClass", description=( "Kubernetes StorageClass name for auto-created PVCs. " "None means use the cluster default. Ignored for Docker volumes." ), ) storage: Optional[str] = Field( None, description=( "Storage capacity request for auto-created PVCs (e.g. '1Gi', '10Gi'). " "Defaults to server-side configured value when omitted. " "Ignored for Docker volumes." ), pattern=r"^\d+(\.\d+)?(Ki|Mi|Gi|Ti|Pi|Ei)?$", ) access_modes: Optional[List[str]] = Field( None, alias="accessModes", description=( "Access modes for auto-created PVCs (e.g. ['ReadWriteOnce']). " "Defaults to ['ReadWriteOnce'] when omitted. Ignored for Docker volumes." ), ) class Config: populate_by_name = True class OSSFS(BaseModel): """ Alibaba Cloud OSS mount backend via ossfs. The runtime mounts a host-side OSS path under ``storage.ossfs_mount_root`` and then bind-mounts the resolved path into the sandbox container. Prefix selection is expressed via ``Volume.subPath``. In Docker runtime, OSSFS backend requires the server host to be Linux with FUSE support. """ bucket: str = Field( ..., description="OSS bucket name.", min_length=3, max_length=63, ) endpoint: str = Field( ..., description="OSS endpoint, e.g. 'oss-cn-hangzhou.aliyuncs.com'.", min_length=1, ) version: Literal["1.0", "2.0"] = Field( "2.0", description="ossfs major version used by runtime mount integration.", ) options: Optional[List[str]] = Field( None, description=( "Additional ossfs mount options. Runtime encodes options by version: " "1.0 => 'ossfs ... -o