1
0
mirror of https://github.com/sredevopsorg/deepseek-kubernetes-sandbox.git synced 2026-11-03 01:13:24 +00:00

feat(skills): add agent-sandbox platform skill (#20)

Add the project-local dsh-agent-sandbox-platform skill covering platform operations, the optional agent-sandbox MCP server, feature-extension recipes, and a read-only preflight. Document project skills in README, docs and AGENTS.md.

Co-authored-by: SREDevOpsAgents <agents@sredevops.org>
This commit is contained in:
Nicolás Georger
2026-10-26 08:10:59 -03:00
committed by GitHub
parent 8681412be4
commit bf24306421
10 changed files with 1046 additions and 0 deletions

View File

@@ -0,0 +1,298 @@
#!/usr/bin/env bash
# Read-only preflight for the DSH agents-as-a-service platform.
#
# Checks the kubectl target, agent-sandbox CRDs/version, warm pools, claims,
# sandboxes, gateway and (optionally) an agent-sandbox MCP server. It never
# mutates the cluster, never reads Secret data, and never port-forwards.
#
# Usage:
# platform-preflight.sh [--context NAME] [--namespace NS] [--pool NAME]
# [--template NAME] [--mcp-url URL] [--help]
#
# Exit codes: 0 = no failures, 1 = at least one failure, 2 = usage error.
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || true)"
CTX=""
NS="${NAMESPACE:-dsh-demo}"
POOL=""
TEMPLATE=""
MCP_URL=""
PASS=0
WARN=0
FAIL=0
usage() {
cat <<'EOF'
Read-only preflight for the DSH agents-as-a-service platform.
Options:
--context NAME kubectl context (default: current context)
--namespace NS namespace to inspect (default: $NAMESPACE or dsh-demo)
--pool NAME check only this warm pool
--template NAME check only this SandboxTemplate
--mcp-url URL also check an MCP server's /healthz and /readyz
--help show this help
The script makes no changes and never reads Secret data.
EOF
}
while [ "$#" -gt 0 ]; do
case "$1" in
--context) CTX="${2:-}"; shift 2 ;;
--namespace) NS="${2:-}"; shift 2 ;;
--pool) POOL="${2:-}"; shift 2 ;;
--template) TEMPLATE="${2:-}"; shift 2 ;;
--mcp-url) MCP_URL="${2:-}"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) echo "unknown argument: $1" >&2; usage >&2; exit 2 ;;
esac
done
if [ -z "$NS" ]; then
echo "namespace must not be empty" >&2
exit 2
fi
section() { printf '\n== %s ==\n' "$1"; }
pass() { PASS=$((PASS + 1)); printf 'PASS %s\n' "$1"; }
warn() { WARN=$((WARN + 1)); printf 'WARN %s\n' "$1"; }
fail() { FAIL=$((FAIL + 1)); printf 'FAIL %s\n' "$1"; }
info() { printf 'INFO %s\n' "$1"; }
command -v kubectl >/dev/null 2>&1 || {
echo "FAIL kubectl is not installed" >&2
exit 1
}
if [ -n "$CTX" ]; then
if ! kubectl config get-contexts -o name 2>/dev/null | grep -Fxq "$CTX"; then
echo "FAIL context '$CTX' is not in the kubeconfig" >&2
exit 1
fi
KUBECTL=(kubectl --context "$CTX" --request-timeout=15s)
else
KUBECTL=(kubectl --request-timeout=15s)
fi
k() { "${KUBECTL[@]}" "$@"; }
section "Target"
if current="$(k config current-context 2>/dev/null)"; then
info "context: $current"
pass "kubeconfig is readable"
else
fail "cannot read the current kubectl context"
fi
if user="$(k auth whoami -o jsonpath='{.status.userInfo.username}' 2>/dev/null)" && [ -n "$user" ]; then
info "identity: $user"
else
fallback_user="$(k config view --minify -o jsonpath='{.users[0].name}' 2>/dev/null || true)"
info "identity: ${fallback_user:-unknown}"
fi
if k get namespace "$NS" -o name >/dev/null 2>&1; then
pass "namespace $NS exists"
else
fail "namespace $NS is missing or not readable"
fi
if [ -n "$REPO_ROOT" ] && [ -f "$REPO_ROOT/versions.env" ]; then
# shellcheck source=/dev/null
. "$REPO_ROOT/versions.env"
info "expected agent-sandbox pin: ${AGENT_SANDBOX_VERSION:-unknown}"
else
warn "versions.env not found; skipping the pin comparison"
fi
section "Capabilities (informational; never widen them)"
for check in "create sandboxclaims" "delete sandboxclaims" "create pods/exec"; do
verb="${check%% *}"
resource="${check#* }"
if [ "$(k auth can-i "$verb" "$resource" -n "$NS" 2>/dev/null || echo unknown)" = "yes" ]; then
info "can $verb $resource in $NS: yes"
else
info "can $verb $resource in $NS: no"
fi
done
if [ "$(k auth can-i get secrets -n "$NS" 2>/dev/null || echo unknown)" = "yes" ]; then
warn "RBAC allows reading Secrets; policy still forbids printing Secret data"
else
info "can get secrets in $NS: no"
fi
section "Agent Sandbox CRDs"
for crd in \
sandboxtemplates.extensions.agents.x-k8s.io \
sandboxwarmpools.extensions.agents.x-k8s.io \
sandboxclaims.extensions.agents.x-k8s.io \
sandboxes.agents.x-k8s.io; do
if k get crd "$crd" -o name >/dev/null 2>&1; then
pass "CRD $crd"
else
fail "CRD $crd is missing or not readable"
fi
done
section "Controller"
controller_ns="agent-sandbox-system"
controller_image="$(k -n "$controller_ns" get deployment agent-sandbox-controller \
-o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/null || true)"
if [ -n "$controller_image" ]; then
info "controller image: $controller_image"
controller_tag="${controller_image##*:}"
if [ -n "${AGENT_SANDBOX_VERSION:-}" ] && [ "$controller_tag" != "$AGENT_SANDBOX_VERSION" ]; then
warn "controller tag '$controller_tag' differs from AGENT_SANDBOX_VERSION '$AGENT_SANDBOX_VERSION'"
else
pass "controller version matches versions.env"
fi
else
warn "controller deployment not found in $controller_ns; cannot verify the installed version"
fi
section "Templates"
templates="$(k -n "$NS" get sandboxtemplates \
-o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null || true)"
if [ -z "$templates" ]; then
warn "no SandboxTemplates in $NS"
fi
if [ -n "$TEMPLATE" ] && ! printf '%s\n' "$templates" | grep -Fxq "$TEMPLATE"; then
fail "SandboxTemplate $TEMPLATE not found in $NS"
fi
for tpl in $templates; do
[ -n "$TEMPLATE" ] && [ "$tpl" != "$TEMPLATE" ] && continue
desc="$(k -n "$NS" get sandboxtemplate "$tpl" \
-o jsonpath='{range .spec.podTemplate.spec.containers[*]}{.name}{":"}{range .ports[*]}{.containerPort}{","}{end}{";"}{end}' \
2>/dev/null || true)"
info "template $tpl containers: ${desc:-<none>}"
case "$desc" in
*sandboxd*|*:8080,*|*:9090,*)
pass "template $tpl exposes a sandboxd runtime (MCP sandboxd-in-cluster)" ;;
*:8888,*)
pass "template $tpl exposes a runtime HTTP port (MCP gateway/direct/in-cluster)" ;;
*:3080,*)
warn "template $tpl is DSH Web only (:3080); MCP execute_command cannot run against it" ;;
*)
warn "template $tpl exposes no known sandbox runtime port" ;;
esac
done
section "Warm pools"
pools="$(k -n "$NS" get sandboxwarmpools \
-o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null || true)"
if [ -z "$pools" ]; then
warn "no SandboxWarmPools in $NS; claims will provision cold"
fi
if [ -n "$POOL" ] && ! printf '%s\n' "$pools" | grep -Fxq "$POOL"; then
fail "SandboxWarmPool $POOL not found in $NS"
fi
for pool in $pools; do
[ -n "$POOL" ] && [ "$pool" != "$POOL" ] && continue
replicas="$(k -n "$NS" get sandboxwarmpool "$pool" -o jsonpath='{.spec.replicas}' 2>/dev/null || true)"
selector="$(k -n "$NS" get sandboxwarmpool "$pool" -o jsonpath='{.status.selector}' 2>/dev/null || true)"
if [ -n "$selector" ]; then
ready="$(k -n "$NS" get sandboxes -l "$selector" \
-o jsonpath='{range .items[*]}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}' \
2>/dev/null | grep -c '^True$' || true)"
else
ready="$(k -n "$NS" get sandboxes -l agents.x-k8s.io/warm-pool-sandbox \
-o jsonpath='{range .items[*]}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}' \
2>/dev/null | grep -c '^True$' || true)"
fi
replicas="${replicas:-0}"
info "pool $pool: $ready/$replicas warm spares Ready"
if [ "$replicas" -eq 0 ]; then
warn "pool $pool has spec.replicas=0; signup will cold-provision"
elif [ "$ready" -lt "$replicas" ]; then
warn "pool $pool is below its desired spare count"
else
pass "pool $pool is at capacity"
fi
done
section "Claims"
claims="$(k -n "$NS" get sandboxclaims \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\t"}{.status.conditions[?(@.type=="Ready")].reason}{"\t"}{.status.sandbox.name}{"\n"}{end}' \
2>/dev/null || true)"
if [ -z "$claims" ]; then
warn "no SandboxClaims in $NS"
else
while IFS=$'\t' read -r name ready reason sandbox; do
[ -n "$name" ] || continue
if [ "$ready" != "True" ]; then
warn "claim $name is not Ready (status='${ready:-unknown}', reason='${reason:-unknown}')"
elif [ -z "$sandbox" ]; then
warn "claim $name is Ready but has no bound sandbox"
else
pass "claim $name -> sandbox $sandbox"
fi
done <<< "$claims"
fi
section "Sandboxes"
sandboxes="$(k -n "$NS" get sandboxes \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.operatingMode}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}' \
2>/dev/null || true)"
if [ -z "$sandboxes" ]; then
warn "no Sandboxes in $NS"
else
while IFS=$'\t' read -r name mode ready; do
[ -n "$name" ] || continue
info "sandbox $name mode=${mode:-Running} ready=${ready:-unknown}"
done <<< "$sandboxes"
fi
section "Storage and Services"
pvc_count="$(k -n "$NS" get pvc -o name 2>/dev/null | wc -l | tr -d ' ')"
svc_count="$(k -n "$NS" get service -o name 2>/dev/null | wc -l | tr -d ' ')"
info "persistent volume claims: ${pvc_count:-0}"
info "services: ${svc_count:-0}"
[ "${pvc_count:-0}" -gt 0 ] || warn "no PVCs in $NS"
[ "${svc_count:-0}" -gt 0 ] || warn "no Services in $NS"
section "Gateway"
if k -n "$NS" get deployment dsh-gateway -o name >/dev/null 2>&1; then
pass "gateway deployment dsh-gateway exists"
if k -n "$NS" get service dsh-gateway -o name >/dev/null 2>&1; then
endpoints="$(k -n "$NS" get endpoints dsh-gateway \
-o jsonpath='{range .subsets[*].addresses[*]}{.ip}{" "}{end}' 2>/dev/null || true)"
if [ -n "$endpoints" ]; then
pass "gateway endpoints: $endpoints"
else
warn "gateway Service has no ready endpoints"
fi
else
warn "gateway Service dsh-gateway is missing"
fi
else
warn "no dsh-gateway deployment; this is a resource-layer-only install"
fi
section "MCP server"
if [ -n "$MCP_URL" ]; then
if ! command -v curl >/dev/null 2>&1; then
fail "curl is required for --mcp-url"
else
base="${MCP_URL%/}"
base="${base%/mcp}"
for endpoint in healthz readyz; do
body="$(curl -fsS --max-time 5 "$base/$endpoint" 2>/dev/null | head -c 300 || true)"
if [ -n "$body" ]; then
pass "MCP /$endpoint: $body"
else
fail "MCP /$endpoint is unreachable at $base/$endpoint"
fi
done
fi
else
info "no --mcp-url supplied; skipping server health checks"
fi
printf '\n== Summary ==\nPASS=%d WARN=%d FAIL=%d\n' "$PASS" "$WARN" "$FAIL"
if [ "$FAIL" -gt 0 ]; then
exit 1
fi
exit 0