Skip to content

feat(api): model CPU and memory as portable resource requirements #2838

Description

@elezar

User Story

As an OpenShell CLI, SDK, or direct API user, I want CPU, memory, and GPU requirements to use one typed portable resource model, so that sandbox workload intent is consistent across drivers and does not require backend-shaped template passthrough.

Problem Statement

OpenShell currently models GPU requests as portable resource intent, but CPU and memory take a different path.

Today:

  • --gpu populates SandboxSpec.resource_requirements.gpu.
  • --cpu and --memory populate SandboxSpec.template.resources.limits as a free-form google.protobuf.Struct.
  • The gateway extracts limits.cpu, limits.memory, requests.cpu, and requests.memory from SandboxTemplate.resources into internal DriverResourceRequirements.
  • Drivers consume CPU and memory from DriverSandboxTemplate.resources, while GPU is consumed from DriverSandboxSpec.resource_requirements.

This makes common portable resources split across two public API surfaces. It also leaves SandboxTemplate.resources acting as both a platform-native escape hatch and the stable path for portable CPU/memory intent.

Impact / Why This Matters

The current model is harder for SDK users, API users, and future template work to reason about. GPU is represented as typed workload intent, while CPU and memory require constructing a Kubernetes-shaped struct even when the target driver is Docker, Podman, or VM.

This also complicates future API cleanup work around sandbox workload templates. First-class templates should be able to store reusable workload resources, but created sandboxes should still persist the resolved portable resource intent in their own spec. A typed compute requirement model gives both inline creates and template-based creates the same resource shape.

Proposed Design

Extend ResourceRequirements with a typed compute resource message for CPU and memory.

Illustrative public proto shape:

message ResourceRequirements {
  // Existing GPU requirements. Presence indicates a GPU request.
  GpuResourceRequirements gpu = 1;

  // Portable CPU and memory requirements.
  ComputeResourceRequirements compute = 2;
}

message ComputeResourceRequirements {
  string cpu_request = 1;
  string cpu_limit = 2;
  string memory_request = 3;
  string memory_limit = 4;
}

Mirror the same semantics in compute_driver.proto, so compute drivers receive CPU, memory, and GPU through DriverSandboxSpec.resource_requirements.

Expected behavior:

  • openshell sandbox create --cpu 2 --memory 4Gi populates resource_requirements.compute.cpu_limit and resource_requirements.compute.memory_limit.
  • openshell sandbox create --gpu continues to populate resource_requirements.gpu.
  • --gpu without a count continues to mean a present GPU request with driver-default count semantics.
  • Kubernetes maps typed compute requirements to pod container requests/limits, preserving today's limit-to-request mirroring when only limits are supplied.
  • Docker and Podman apply supported CPU and memory limits from typed compute requirements.
  • VM must either map typed CPU/memory requirements to VM sizing or reject unsupported requirements clearly; it should not silently ignore typed portable requirements.
  • SandboxTemplate.resources remains available temporarily for compatibility and platform-native passthrough.
  • If both typed compute requirements and template CPU/memory resources are provided for the same sandbox, validation should reject conflicting values instead of silently choosing one.

If the sandbox workload template work from #2833 lands first, this issue should align inline sandbox creates and resolved sandbox specs with the typed resource shape used by workload templates. If the breaking cleanup direction from #2781 is pursued, this issue should fold naturally into SandboxWorkloadConfig.resources.

Acceptance Criteria

  • Public protobufs model CPU and memory as typed portable resource requirements.
  • Compute-driver protobufs model CPU and memory under the driver resource requirements envelope.
  • CLI --cpu and --memory populate typed compute requirements instead of SandboxTemplate.resources.
  • Existing --gpu behavior remains user-compatible.
  • Gateway translation passes CPU, memory, and GPU through resource requirements.
  • Legacy CPU/memory extraction from SandboxTemplate.resources is retained only as a compatibility path, with clear precedence or conflict validation.
  • Kubernetes, Docker, and Podman consume typed compute requirements with behavior equivalent to today's CLI-generated CPU/memory requests.
  • VM behavior for typed CPU/memory is explicit: implemented sizing or clear rejection.
  • SDKs expose typed CPU/memory fields without requiring raw Struct construction.
  • Docs explain portable resource requirements versus platform-native template resources.
  • Tests cover CLI request construction, gateway translation, driver validation, driver realization, and conflict handling.

Alternatives Considered

Keep CPU and memory in SandboxTemplate.resources. This preserves today's behavior but keeps portable resource intent coupled to a platform-native struct and makes SDK usage awkward.

Add top-level cpu and memory fields to SandboxSpec. This is simpler, but it repeats the older GPU-specific pattern and does not scale to request/limit semantics or future resource domains.

Use only the SandboxResources shape from workload templates. That may be the right end-state after template cleanup, but the current API already has SandboxSpec.resource_requirements as the portable resource envelope. Adding compute there is the smallest compatible step.

Expose a JSON resource flag. RFC 0004 explicitly avoids JSON-formatted portable resource requests because common resources should be typed.

Agent Investigation

Current local code shows the split:

  • CLI --gpu becomes GpuResourceRequirements and is wrapped in SandboxSpec.resource_requirements.
  • CLI --cpu and --memory become SandboxTemplate.resources.limits entries.
  • The public ResourceRequirements message currently contains only GPU.
  • The gateway extracts CPU/memory from SandboxTemplate.resources into DriverResourceRequirements.
  • Docker and Podman apply CPU/memory from driver template resources.
  • Kubernetes renders CPU/memory from driver template resources and GPU from driver resource requirements into pod container resources.
  • VM uses GPU requirements for GPU-specific validation/sizing, but currently accepts CPU/memory template resources as a no-op.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions