Newer
Older
openstack-caracal-ipv4 / clientdocs / scripts / smoke-test.sh
#!/usr/bin/env bash
# smoke-test.sh -- Omega Cloud environment health check (yours to run; read-only).
#
# What: proves your automation credential and environment work end to end:
#         1. issue a token (authentication)
#         2. list the service catalog (endpoint discovery)
#         3. read your quota/limits envelope (capacity visibility)
#       These are rows A1/A4/A5 of the Acceptance Checklist and the first
#       triage steps of the CI/Automation Integration Guide.
# Why:  authentication and quota explain most sudden pipeline breakage --
#       run this first whenever automation against your environment fails,
#       and as the opening stage of every pipeline.
# Safety: READ-ONLY. This script creates, changes, and deletes nothing.
#
# Auth: your normal OpenStack client environment -- either OS_CLOUD (from a
#       clouds.yaml) or the OS_* variables from the CI/Automation Integration
#       Guide. No arguments needed.
# Exit: 0 all checks passed | 1 a check failed | 2 environment not set up.
set -uo pipefail

command -v openstack >/dev/null 2>&1 || {
  echo "SETUP: the 'openstack' client is not installed (pip install python-openstackclient)"; exit 2; }
command -v python3 >/dev/null 2>&1 || { echo "SETUP: python3 is required"; exit 2; }
if [ -z "${OS_CLOUD:-}" ] && [ -z "${OS_AUTH_URL:-}" ]; then
  echo "SETUP: no OpenStack environment found."
  echo "  Either: export OS_CLOUD=<your cloud name from clouds.yaml>"
  echo "  Or:     export the OS_* variables from the CI/Automation Integration Guide."
  exit 2
fi

WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
OS_ERR="$WORK/stderr.txt"
FAILED=0

# Structured captures take stdout ONLY; stderr goes to a file so client
# warnings and notices can never corrupt the parsed output.
cap() { # cap <var> <openstack args...>
  local __v="$1"; shift
  local out rc
  out=$(openstack "$@" </dev/null 2>"$OS_ERR"); rc=$?
  printf -v "$__v" '%s' "$out"
  return "$rc"
}
oerr() { head -1 "$OS_ERR" 2>/dev/null || true; }

echo "=== Omega Cloud smoke test ($(date -u +%Y-%m-%dT%H:%M:%SZ)) ==="

# ---- 1/3 authentication --------------------------------------------------
if cap TOK token issue -f json; then
  PROJECT_ID=$(printf '%s' "$TOK" | python3 -c '
import json,sys
try: print(json.load(sys.stdin).get("project_id",""))
except Exception: pass')
  if [ -n "$PROJECT_ID" ]; then
    echo "  [PASS] 1/3 token issued, scoped to your project ($PROJECT_ID)"
  else
    echo "  [FAIL] 1/3 token issue returned output the client could not parse"
    [ -s "$OS_ERR" ] && echo "         client said: $(oerr)"
    FAILED=1
  fi
else
  echo "  [FAIL] 1/3 authentication failed"
  echo "         client said: $(oerr)"
  echo "         Most common causes (check in this order):"
  echo "           - the application credential was revoked or has expired"
  echo "             (whoever rotates credentials on your side will know)"
  echo "           - the CA bundle is missing from this environment"
  echo "             (OS_CACERT, or 'cacert' in clouds.yaml -- do not disable"
  echo "              certificate verification instead)"
  echo "           - the credential id/secret were not injected into this job"
  FAILED=1
fi

# ---- 2/3 endpoint discovery ----------------------------------------------
if [ "$FAILED" -eq 0 ]; then
  if cap CAT catalog list -f json; then
    SUMMARY=$(printf '%s' "$CAT" | python3 -c '
import json,sys
try: rows=json.load(sys.stdin)
except Exception: sys.exit(1)
types=sorted({r.get("Type","?") for r in rows})
print("%d services: %s" % (len(rows), ", ".join(types)))') || SUMMARY=""
    if [ -n "$SUMMARY" ]; then
      echo "  [PASS] 2/3 service catalog visible ($SUMMARY)"
    else
      echo "  [FAIL] 2/3 catalog list returned unparseable output: $(oerr)"
      FAILED=1
    fi
  else
    echo "  [FAIL] 2/3 catalog list failed: $(oerr)"
    FAILED=1
  fi
else
  echo "  [SKIP] 2/3 catalog list (blocked: authentication failed)"
fi

# ---- 3/3 quota envelope ---------------------------------------------------
if [ "$FAILED" -eq 0 ]; then
  if cap LIM limits show --absolute -f json; then
    USAGE=$(printf '%s' "$LIM" | python3 -c '
import json,sys
try: d={r.get("Name"): r.get("Value") for r in json.load(sys.stdin)}
except Exception: sys.exit(1)
def g(k): return d.get(k, "?")
print("instances %s/%s, cores %s/%s, ram %s/%s MB" % (
  g("totalInstancesUsed"), g("maxTotalInstances"),
  g("totalCoresUsed"), g("maxTotalCores"),
  g("totalRAMUsed"), g("maxTotalRAMSize")))') || USAGE=""
    if [ -n "$USAGE" ]; then
      echo "  [PASS] 3/3 quota envelope visible (used/limit: $USAGE)"
      echo "         Quota-exceeded errors in pipelines are actionable, not"
      echo "         retryable: clean up leaked resources or request a raise."
    else
      echo "  [FAIL] 3/3 limits show returned unparseable output: $(oerr)"
      FAILED=1
    fi
  else
    echo "  [FAIL] 3/3 limits show failed: $(oerr)"
    FAILED=1
  fi
else
  echo "  [SKIP] 3/3 limits show (blocked by an earlier failure)"
fi

echo
if [ "$FAILED" -eq 0 ]; then
  echo "RESULT: SMOKE TEST PASS (authentication, catalog, quota all healthy)"
  exit 0
fi
echo "RESULT: SMOKE TEST FAIL"
echo "  Reminders from the integration guide:"
echo "  - A permission error on identity, quota, or cluster operations is the"
echo "    platform working as designed, not an outage."
echo "  - Anything that looks like a platform fault: send the EXACT command"
echo "    and the EXACT error text to your account contact. Verbatim errors"
echo "    get fast answers; paraphrased ones do not."
exit 1