diff --git a/.github/workflows/real-e2e.yml b/.github/workflows/real-e2e.yml index e88c7f66..c073ea59 100644 --- a/.github/workflows/real-e2e.yml +++ b/.github/workflows/real-e2e.yml @@ -90,7 +90,6 @@ jobs: runs-on: self-hosted env: UV_BIN: /home/admin/.local/bin - JAVA_VERSION: "17.0.14+7" steps: - name: Checkout code uses: actions/checkout@v6 @@ -102,24 +101,17 @@ jobs: uv --version uv run python --version - - name: Set up JDK - run: | - # Adoptium Temurin JDK 17 for Linux x64 - JAVA_MAJOR="${JAVA_VERSION%%.*}" - JAVA_URL_VERSION=$(echo "${JAVA_VERSION}" | sed 's/+/%2B/') - JAVA_DIR="/home/admin/.local/jdk-${JAVA_VERSION}" - if [ -x "${JAVA_DIR}/bin/java" ]; then - echo "JDK ${JAVA_VERSION} already cached" - else - echo "Downloading Temurin JDK ${JAVA_VERSION}..." - mkdir -p /home/admin/.local - curl -fsSL "https://api.adoptium.net/v3/binary/version/jdk-${JAVA_URL_VERSION}/linux/x64/jdk/hotspot/normal/eclipse?project=jdk" \ - | tar -xzf - -C /home/admin/.local/ - fi - echo "${JAVA_DIR}/bin" >> "$GITHUB_PATH" - echo "JAVA_HOME=${JAVA_DIR}" >> "$GITHUB_ENV" - export PATH="${JAVA_DIR}/bin:${PATH}" - java -version + - name: Set up JDK 8 + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: "8" + + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: "17" - name: Clean up previous E2E resources run: | @@ -131,6 +123,7 @@ jobs: GRADLE_USER_HOME: ${{ github.workspace }}/.gradle-user-home run: | set -e + export GRADLE_OPTS="-Dorg.gradle.java.installations.auto-detect=true -Dorg.gradle.java.installations.auto-download=false -Dorg.gradle.java.installations.paths=${JAVA_HOME_8_X64},${JAVA_HOME_17_X64}" # Create config file cat < ~/.sandbox.toml diff --git a/examples/README.md b/examples/README.md index 44780b5e..ea17791f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,6 +7,7 @@ Examples for common OpenSandbox use cases. Each subdirectory contains runnable c - Kubernetes [**agent-sandbox**](agent-sandbox): Create a kubernetes-sigs/agent-sandbox instance and run a command - 🧪 [**code-interpreter**](code-interpreter): Code Interpreter SDK singleton example - 💾 [**host-volume-mount**](host-volume-mount): Mount host directories into sandboxes (read-write, read-only, subpath) +- ☁️ [**docker-ossfs-volume-mount**](docker-ossfs-volume-mount): Mount OSSFS volumes in Docker runtime (inline credentials, subpath, sharing) - 🎯 [**rl-training**](rl-training): Reinforcement learning training loop inside a sandbox - Claude [**claude-code**](claude-code): Call Claude (Anthropic) API/CLI within the sandbox - iFlow [**iflow-cli**](iflow-cli): CLI invocation template for iFlow/custom HTTP LLM services diff --git a/examples/docker-ossfs-volume-mount/README.md b/examples/docker-ossfs-volume-mount/README.md new file mode 100644 index 00000000..62628ed2 --- /dev/null +++ b/examples/docker-ossfs-volume-mount/README.md @@ -0,0 +1,112 @@ +# Docker OSSFS Volume Mount Example + +This example demonstrates how to use the new SDK `ossfs` volume model to mount Alibaba Cloud OSS into sandboxes on Docker runtime. + +## What this example covers + +1. **Basic read-write mount** on an OSSFS backend. +2. **Cross-sandbox sharing** on the same OSSFS backend path. +3. **Two mounts, different OSS prefixes via `subPath`**. + +## Prerequisites + +### 1) Start OpenSandbox server (Docker runtime) + +Make sure your server host has: + +- Linux host OS (OSSFS backend is not supported when OpenSandbox Server runs on Windows) +- `ossfs` installed +- FUSE support enabled +- writable local mount root for OSSFS (default `storage.ossfs_mount_root=/mnt/ossfs`) + +`storage.ossfs_mount_root` is **optional** if you use the default `/mnt/ossfs`. +Even with on-demand mounting, the runtime still needs a deterministic host-side +base directory to place dynamic mounts (`//`). + +Optional config example: + +```toml +[runtime] +type = "docker" + +[storage] +ossfs_mount_root = "/mnt/ossfs" +``` + +Then start the server: + +```bash +opensandbox-server +``` + +### 2) Install Python SDK + +```bash +uv pip install opensandbox +``` + +If your PyPI version does not include OSSFS volume models yet, install from source: + +```bash +pip install -e sdks/sandbox/python +``` + +### 3) Prepare OSS credentials and target path + +```bash +export SANDBOX_DOMAIN=localhost:8080 +export SANDBOX_API_KEY=your-api-key +export SANDBOX_IMAGE=ubuntu + +export OSS_BUCKET=your-bucket +export OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com +export OSS_ACCESS_KEY_ID=your-ak +export OSS_ACCESS_KEY_SECRET=your-sk +``` + +## Run + +```bash +uv run python examples/docker-ossfs-volume-mount/main.py +``` + +## Minimal SDK usage snippet + +```python +from opensandbox import Sandbox +from opensandbox.models.sandboxes import OSSFS, Volume + +sandbox = await Sandbox.create( + image="ubuntu", + volumes=[ + Volume( + name="oss-data", + ossfs=OSSFS( + bucket="your-bucket", + endpoint="oss-cn-hangzhou.aliyuncs.com", + # version="2.0", # optional, default is "2.0" + accessKeyId="your-ak", + accessKeySecret="your-sk", + ), + mountPath="/mnt/data", + subPath="train", # optional + readOnly=False, # optional + ) + ], +) +``` + +## Notes + +- Current implementation supports **inline credentials only** (`accessKeyId`/`accessKeySecret`). +- Mounting is **on-demand** in Docker runtime (mount-or-reuse), not pre-mounted for all buckets. +- `ossfs.version` exists in API/SDK with enum `"1.0" | "2.0"`, and defaults to `"2.0"` when omitted. +- Docker runtime now applies **version-specific mount argument encoding**: + - `1.0`: mounts via `ossfs ... -o