mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-20 06:00:06 +08:00
131 lines
3.6 KiB
Bash
Executable File
131 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# Integration test for building a custom container image and running a sandbox
|
|
# with it.
|
|
#
|
|
# Verifies the full flow:
|
|
# nemoclaw sandbox create --from <Dockerfile> -- <cmd>
|
|
#
|
|
# Prerequisites:
|
|
# - A running nemoclaw cluster (nemoclaw cluster admin deploy)
|
|
# - Docker daemon running (for image build)
|
|
# - The `nemoclaw` binary on PATH (or set NAV_BIN)
|
|
#
|
|
# Usage:
|
|
# ./e2e/bash/test_sandbox_custom_image.sh
|
|
|
|
set -euo pipefail
|
|
|
|
###############################################################################
|
|
# Configuration
|
|
###############################################################################
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
|
|
if [[ -n "${NAV_BIN:-}" ]]; then
|
|
NAV="${NAV_BIN}"
|
|
elif [[ -x "${PROJECT_ROOT}/target/debug/nemoclaw" ]]; then
|
|
NAV="${PROJECT_ROOT}/target/debug/nemoclaw"
|
|
else
|
|
NAV="nemoclaw"
|
|
fi
|
|
|
|
SANDBOX_NAME=""
|
|
TMPDIR_ROOT=""
|
|
|
|
###############################################################################
|
|
# Helpers
|
|
###############################################################################
|
|
|
|
info() { printf '==> %s\n' "$*" >&2; }
|
|
error() { printf 'ERROR: %s\n' "$*" >&2; }
|
|
|
|
strip_ansi() {
|
|
sed $'s/\x1b\\[[0-9;]*m//g'
|
|
}
|
|
|
|
cleanup() {
|
|
local exit_code=$?
|
|
|
|
if [[ -n "${SANDBOX_NAME}" ]]; then
|
|
info "Deleting sandbox ${SANDBOX_NAME}"
|
|
"${NAV}" sandbox delete "${SANDBOX_NAME}" 2>/dev/null || true
|
|
fi
|
|
|
|
if [[ -n "${TMPDIR_ROOT}" && -d "${TMPDIR_ROOT}" ]]; then
|
|
rm -rf "${TMPDIR_ROOT}"
|
|
fi
|
|
|
|
if [[ ${exit_code} -eq 0 ]]; then
|
|
info "PASS"
|
|
else
|
|
error "FAIL (exit ${exit_code})"
|
|
fi
|
|
exit "${exit_code}"
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
|
|
###############################################################################
|
|
# Step 1 — Create a minimal Dockerfile for testing
|
|
###############################################################################
|
|
|
|
info "Creating temporary Dockerfile"
|
|
|
|
TMPDIR_ROOT=$(mktemp -d)
|
|
DOCKERFILE="${TMPDIR_ROOT}/Dockerfile"
|
|
|
|
cat > "${DOCKERFILE}" <<'DOCKERFILE_CONTENT'
|
|
FROM python:3.12-slim
|
|
|
|
# Create the sandbox user/group so the supervisor can switch to it.
|
|
RUN groupadd -g 1000 sandbox && \
|
|
useradd -m -u 1000 -g sandbox sandbox
|
|
|
|
# Write a marker file so we can verify this is our custom image.
|
|
RUN echo "custom-image-e2e-marker" > /opt/marker.txt
|
|
|
|
CMD ["sleep", "infinity"]
|
|
DOCKERFILE_CONTENT
|
|
|
|
###############################################################################
|
|
# Step 2 — Create a sandbox from the Dockerfile and verify it works
|
|
###############################################################################
|
|
|
|
info "Creating sandbox from Dockerfile"
|
|
|
|
CREATE_LOG=$(mktemp)
|
|
if ! "${NAV}" sandbox create \
|
|
--from "${DOCKERFILE}" \
|
|
-- cat /opt/marker.txt \
|
|
> "${CREATE_LOG}" 2>&1; then
|
|
error "Sandbox create failed"
|
|
cat "${CREATE_LOG}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Parse sandbox name from the create output for cleanup.
|
|
SANDBOX_NAME=$(
|
|
strip_ansi < "${CREATE_LOG}" | awk '/Name:/ { print $NF }'
|
|
) || true
|
|
|
|
info "Verifying marker file from custom image"
|
|
|
|
# The sandbox ran `cat /opt/marker.txt` — check that the expected marker
|
|
# appears in the output.
|
|
if ! strip_ansi < "${CREATE_LOG}" | grep -q "custom-image-e2e-marker"; then
|
|
error "Marker file content not found in sandbox output"
|
|
cat "${CREATE_LOG}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
info "Custom image marker verified"
|
|
|
|
###############################################################################
|
|
# Cleanup is handled by the EXIT trap.
|
|
###############################################################################
|