From 31d69ef22035ff5cbffc5f1604c555c5634869fa Mon Sep 17 00:00:00 2001 From: Aisha Date: Tue, 10 Mar 2026 21:41:01 +0400 Subject: [PATCH 1/7] use edge urls --- README.md | 4 +- skills/building-dashboards/README.md | 3 +- skills/controlling-costs/README.md | 3 +- skills/query-metrics/README.md | 2 +- skills/query-metrics/scripts/setup | 2 +- skills/spl-to-apl/README.md | 2 +- skills/sre/README.md | 2 +- skills/sre/reference/api-capabilities.md | 9 ++- skills/sre/reference/axiom.md | 9 ++- skills/sre/scripts/axiom-api | 24 ++++++- skills/sre/scripts/axiom-link | 2 +- skills/sre/scripts/axiom-query | 12 +++- skills/sre/scripts/resolve-url | 89 ++++++++++++++++++++++++ 13 files changed, 141 insertions(+), 22 deletions(-) create mode 100755 skills/sre/scripts/resolve-url diff --git a/README.md b/README.md index f16603f..7c54737 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,8 @@ org_id = "your-staging-org-id" ``` **To get these values:** -1. **org_id**: Settings → Organization → Copy the org ID (or from URL: `app.axiom.co/{org_id}/...`) -2. **token**: Settings → Profile → Personal Access Tokens → Create token (use a Personal Access Token, not an API token, for full query access) +- **`org_id`** - The organization ID. Get it from Settings → Organization. +- **`token`** - Use an advanced API token with minimal privileges. The deployment name (e.g., `prod`, `staging`) is passed to scripts: `scripts/axiom-query prod "..."` diff --git a/skills/building-dashboards/README.md b/skills/building-dashboards/README.md index 8cb0e35..0145f29 100644 --- a/skills/building-dashboards/README.md +++ b/skills/building-dashboards/README.md @@ -34,7 +34,8 @@ token = "xaat-your-api-token" org_id = "your-org-id" ``` -Get your org_id from Settings → Organization. For the token, use a **Personal Access Token** (Settings → Profile → Personal Access Tokens) for full query access. +- **`org_id`** - The organization ID. Get it from Settings → Organization. +- **`token`** - Use an advanced API token with minimal privileges. **Tip:** Run `scripts/setup` from the `axiom-sre` skill for interactive configuration. diff --git a/skills/controlling-costs/README.md b/skills/controlling-costs/README.md index 403e5d0..f4c6583 100644 --- a/skills/controlling-costs/README.md +++ b/skills/controlling-costs/README.md @@ -35,7 +35,8 @@ token = "xaat-your-api-token" org_id = "your-org-id" ``` -Get your org_id from Settings → Organization. For the token, use a **Personal Access Token** (Settings → Profile → Personal Access Tokens) for full query access. +- **`org_id`** - The organization ID. Get it from Settings → Organization. +- **`token`** - Use an advanced API token with minimal privileges. **Tip:** Run `scripts/setup` from the `axiom-sre` skill for interactive configuration. diff --git a/skills/query-metrics/README.md b/skills/query-metrics/README.md index 778314f..ff03874 100644 --- a/skills/query-metrics/README.md +++ b/skills/query-metrics/README.md @@ -36,7 +36,7 @@ token = "xaat-your-api-token" org_id = "your-org-id" ``` -Get your org_id from Settings → Organization. For the token, use a **Personal Access Token** (Settings → Profile → Personal Access Tokens) for full query access. +Get your org_id from Settings → Organization. For the token, create a scoped **API token** (Settings → API Tokens) with the permissions your workflow needs. Avoid Personal Access Tokens for automated tooling. **Tip:** Run `scripts/setup` from the `axiom-sre` skill for interactive configuration. diff --git a/skills/query-metrics/scripts/setup b/skills/query-metrics/scripts/setup index 6bedb63..7467df3 100755 --- a/skills/query-metrics/scripts/setup +++ b/skills/query-metrics/scripts/setup @@ -70,7 +70,7 @@ org_id = "your-org-id" EOF echo "" echo "Get your org_id from Settings → Organization." - echo "For the token, use a Personal Access Token (Settings → Profile → Personal Access Tokens)." + echo "For the token, create a scoped API token (Settings → API Tokens) with the permissions your workflow needs." fi echo "" diff --git a/skills/spl-to-apl/README.md b/skills/spl-to-apl/README.md index 3f8921e..6280c35 100644 --- a/skills/spl-to-apl/README.md +++ b/skills/spl-to-apl/README.md @@ -50,7 +50,7 @@ token = "xaat-your-api-token" org_id = "your-org-id" ``` -Get your org_id from Settings → Organization. For the token, use a **Personal Access Token** (Settings → Profile → Personal Access Tokens) for full query access. +Get your org_id from Settings → Organization. For the token, create a scoped **API token** (Settings → API Tokens) with the permissions your workflow needs. Avoid Personal Access Tokens for automated tooling. ## Related Skills diff --git a/skills/sre/README.md b/skills/sre/README.md index 7abbebd..90077f3 100644 --- a/skills/sre/README.md +++ b/skills/sre/README.md @@ -45,7 +45,7 @@ token = "xaat-your-api-token" org_id = "your-org-id" ``` -Get your org_id from Settings → Organization. For the token, use a **Personal Access Token** (Settings → Profile → Personal Access Tokens) for full query access. +Get your org_id from Settings → Organization. For the token, create a scoped **API token** (Settings → API Tokens) with the permissions your workflow needs. Avoid Personal Access Tokens for automated tooling. ## Usage diff --git a/skills/sre/reference/api-capabilities.md b/skills/sre/reference/api-capabilities.md index ff08146..2fbae87 100644 --- a/skills/sre/reference/api-capabilities.md +++ b/skills/sre/reference/api-capabilities.md @@ -1,13 +1,12 @@ # Axiom API Capabilities -Summary of all operations available via Axiom API with a personal access token (PAT). +Summary of all operations available via Axiom API. -**Base URL:** `https://api.axiom.co` (for all endpoints except ingestion) -**Ingest URL:** Use edge deployment domain (e.g., `https://us-east-1.aws.edge.axiom.co`) +**Base URL:** `https://api.axiom.co` (for management endpoints) +**Query & Ingest URL:** Auto-resolved per dataset via `scripts/resolve-url` **Authentication:** -- PAT: `Authorization: Bearer $PAT` + `x-axiom-org-id: $ORG_ID` -- API Token: `Authorization: Bearer $API_TOKEN` +- `Authorization: Bearer $API_TOKEN` — use an advanced API token with minimal privileges --- diff --git a/skills/sre/reference/axiom.md b/skills/sre/reference/axiom.md index db9b12e..5b78cd0 100644 --- a/skills/sre/reference/axiom.md +++ b/skills/sre/reference/axiom.md @@ -1,13 +1,12 @@ # Axiom API Capabilities -Summary of all operations available via Axiom API with a personal access token (PAT). +Summary of all operations available via Axiom API. -**Base URL:** `https://api.axiom.co` (for all endpoints except ingestion) -**Ingest URL:** Use edge deployment domain (e.g., `https://us-east-1.aws.edge.axiom.co`) +**Base URL:** `https://api.axiom.co` (for management endpoints) +**Query & Ingest URL:** Auto-resolved per dataset via `scripts/resolve-url` **Authentication:** -- PAT: `Authorization: Bearer $PAT` + `x-axiom-org-id: $ORG_ID` -- API Token: `Authorization: Bearer $API_TOKEN` +- `Authorization: Bearer $API_TOKEN` — use an advanced API token with minimal privileges --- diff --git a/skills/sre/scripts/axiom-api b/skills/sre/scripts/axiom-api index f4bf71e..a7c7d10 100755 --- a/skills/sre/scripts/axiom-api +++ b/skills/sre/scripts/axiom-api @@ -20,8 +20,28 @@ fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")" +# Auto-resolve edge URL for query and ingest endpoints +REQUEST_URL="$AXIOM_URL" +case "$ENDPOINT" in + /v1/datasets/_apl*|/v1/ingest/*) + DATASET="" + if [[ "$ENDPOINT" == /v1/ingest/* ]]; then + DATASET="${ENDPOINT#/v1/ingest/}" + DATASET="${DATASET%%[?/]*}" + elif [[ -n "$BODY" ]]; then + DATASET=$(echo "$BODY" | jq -r '.apl // empty' 2>/dev/null | grep -oE "^\['[^']+'\]|^\[\"[^\"]+\"\]|^\[[a-zA-Z0-9_-]+\]" | head -1 | tr -d "[]'\"" || true) + fi + if [[ -n "$DATASET" ]]; then + RESOLVED=$("$SCRIPT_DIR/resolve-url" "$DEPLOYMENT" "$DATASET" 2>/dev/null || true) + if [[ -n "$RESOLVED" ]]; then + REQUEST_URL="$RESOLVED" + fi + fi + ;; +esac + if [[ -n "$BODY" ]]; then - "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" -d "$BODY" "${AXIOM_URL}${ENDPOINT}" + "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" -d "$BODY" "${REQUEST_URL}${ENDPOINT}" else - "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" "${AXIOM_URL}${ENDPOINT}" + "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" "${REQUEST_URL}${ENDPOINT}" fi diff --git a/skills/sre/scripts/axiom-link b/skills/sre/scripts/axiom-link index 266ee62..25bc9cc 100755 --- a/skills/sre/scripts/axiom-link +++ b/skills/sre/scripts/axiom-link @@ -37,10 +37,10 @@ fi # Derive web UI URL from configured API URL # Replace "api." with "app." in the domain # Examples: +# https://api.axiom.co → https://app.axiom.co # https://api.staging.axiom.co → https://app.staging.axiom.co # https://api.dev.axiom.co → https://app.dev.axiom.co # https://cloud.axiom.co → https://app.axiom.co -# https://api.axiom.co → https://app.axiom.co if [[ "$URL" == *"cloud.axiom.co"* ]]; then BASE_URL="https://app.axiom.co" elif [[ "$URL" == https://api.* ]]; then diff --git a/skills/sre/scripts/axiom-query b/skills/sre/scripts/axiom-query index c15f737..a0471d3 100755 --- a/skills/sre/scripts/axiom-query +++ b/skills/sre/scripts/axiom-query @@ -148,9 +148,19 @@ cleanup() { } trap cleanup EXIT +# Auto-resolve edge URL +QUERY_URL="$AXIOM_URL" +DATASET=$(echo "$APL" | grep -oE "^\['[^']+'\]|^\[\"[^\"]+\"\]|^\[[a-zA-Z0-9_-]+\]" | head -1 | tr -d "[]'\"" || true) +if [[ -n "$DATASET" ]]; then + RESOLVED=$("$SCRIPT_DIR/resolve-url" "$DEPLOYMENT" "$DATASET" 2>/dev/null || true) + if [[ -n "$RESOLVED" ]]; then + QUERY_URL="$RESOLVED" + fi +fi + # Execute query and pipe to formatter HTTP_CODE=$(curl -sS -o "$RESP_BODY" -D "$RESP_HEADERS" -w "%{http_code}" \ - -X POST "$AXIOM_URL/v1/datasets/_apl?format=tabular" \ + -X POST "$QUERY_URL/v1/datasets/_apl?format=tabular" \ -H "Authorization: Bearer $AXIOM_TOKEN" \ -H "X-Axiom-Org-Id: $AXIOM_ORG_ID" \ -H "Content-Type: application/json" \ diff --git a/skills/sre/scripts/resolve-url b/skills/sre/scripts/resolve-url new file mode 100755 index 0000000..da1079a --- /dev/null +++ b/skills/sre/scripts/resolve-url @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# resolve-url: Resolve the regional edge URL for a dataset +# +# Usage: resolve-url +# +# Two-step resolution: +# 1. GET /v1/datasets → find dataset's region (e.g. cloud.us-east-1.aws) +# 2. GET /api/internal/regions/axiom → map region to edge domain +# +# Both steps are cached to avoid repeated API calls. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +DEPLOYMENT="${1:-}" +DATASET="${2:-}" + +if [[ -z "$DEPLOYMENT" || -z "$DATASET" ]]; then + echo "Usage: resolve-url " >&2 + exit 1 +fi + +CACHE_DIR="${TMPDIR:-/tmp}/axiom-edge-cache" + +# Check dataset edge URL cache (valid for 1 hour) +DATASET_CACHE="$CACHE_DIR/edge__${DEPLOYMENT}__${DATASET}" +if [[ -f "$DATASET_CACHE" ]]; then + if [[ "$(uname)" == "Darwin" ]]; then + AGE=$(( $(date +%s) - $(stat -f %m "$DATASET_CACHE") )) + else + AGE=$(( $(date +%s) - $(stat -c %Y "$DATASET_CACHE") )) + fi + if [[ $AGE -lt 3600 ]]; then + cat "$DATASET_CACHE" + exit 0 + fi +fi + +# Load config to get the base URL as fallback +eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")" + +# Step 1: get dataset region +REGION=$("$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X GET "${AXIOM_URL}/v1/datasets" \ + | jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .region // empty' 2>/dev/null) + +if [[ -z "$REGION" || "$REGION" == "null" ]]; then + echo "$AXIOM_URL" + exit 0 +fi + +# Step 2: look up edge domain from regions API (cached 24h per deployment) +REGIONS_CACHE="$CACHE_DIR/regions__${DEPLOYMENT}" +REGIONS_JSON="" +if [[ -f "$REGIONS_CACHE" ]]; then + if [[ "$(uname)" == "Darwin" ]]; then + AGE=$(( $(date +%s) - $(stat -f %m "$REGIONS_CACHE") )) + else + AGE=$(( $(date +%s) - $(stat -c %Y "$REGIONS_CACHE") )) + fi + if [[ $AGE -lt 86400 ]]; then + REGIONS_JSON=$(cat "$REGIONS_CACHE") + fi +fi + +if [[ -z "$REGIONS_JSON" ]]; then + APP_URL="${AXIOM_URL/api./app.}" + REGIONS_JSON=$("$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X GET "${APP_URL}/api/internal/regions/axiom" 2>/dev/null) || true + if [[ -n "$REGIONS_JSON" ]]; then + mkdir -p "$CACHE_DIR" + echo "$REGIONS_JSON" > "$REGIONS_CACHE" + fi +fi + +EDGE_DOMAIN="" +if [[ -n "$REGIONS_JSON" ]]; then + EDGE_DOMAIN=$(echo "$REGIONS_JSON" | jq -r --arg region "$REGION" '.axiom[] | select(.id == $region) | .domain // empty' 2>/dev/null) +fi + +if [[ -z "$EDGE_DOMAIN" ]]; then + echo "$AXIOM_URL" + exit 0 +fi + +# Cache the resolved edge URL +mkdir -p "$CACHE_DIR" +echo "$EDGE_DOMAIN" > "$DATASET_CACHE" + +echo "$EDGE_DOMAIN" From 01af45de1b64ecf7b1afc1e80d4894fe8f32e3cd Mon Sep 17 00:00:00 2001 From: Aisha Date: Tue, 10 Mar 2026 21:55:11 +0400 Subject: [PATCH 2/7] use edgeDeployment --- skills/query-metrics/scripts/resolve-url | 2 +- skills/sre/scripts/axiom-api | 11 ++++++++--- skills/sre/scripts/axiom-query | 7 ++++--- skills/sre/scripts/resolve-url | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/skills/query-metrics/scripts/resolve-url b/skills/query-metrics/scripts/resolve-url index 29f3085..3e47368 100755 --- a/skills/query-metrics/scripts/resolve-url +++ b/skills/query-metrics/scripts/resolve-url @@ -36,7 +36,7 @@ extract_value() { FALLBACK_URL=$(extract_value "url") REGION=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET /v1/datasets \ - | jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .region // empty') + | jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .edgeDeployment // .region // empty') if [[ -z "$REGION" || "$REGION" == "null" ]]; then echo "$FALLBACK_URL" diff --git a/skills/sre/scripts/axiom-api b/skills/sre/scripts/axiom-api index a7c7d10..e64ab55 100755 --- a/skills/sre/scripts/axiom-api +++ b/skills/sre/scripts/axiom-api @@ -21,7 +21,9 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")" # Auto-resolve edge URL for query and ingest endpoints +# Edge uses /v1/query/_apl for queries (not /v1/datasets/_apl) REQUEST_URL="$AXIOM_URL" +REQUEST_ENDPOINT="$ENDPOINT" case "$ENDPOINT" in /v1/datasets/_apl*|/v1/ingest/*) DATASET="" @@ -33,15 +35,18 @@ case "$ENDPOINT" in fi if [[ -n "$DATASET" ]]; then RESOLVED=$("$SCRIPT_DIR/resolve-url" "$DEPLOYMENT" "$DATASET" 2>/dev/null || true) - if [[ -n "$RESOLVED" ]]; then + if [[ -n "$RESOLVED" && "$RESOLVED" != "$AXIOM_URL" ]]; then REQUEST_URL="$RESOLVED" + if [[ "$ENDPOINT" == /v1/datasets/_apl* ]]; then + REQUEST_ENDPOINT="/v1/query/_apl${ENDPOINT#/v1/datasets/_apl}" + fi fi fi ;; esac if [[ -n "$BODY" ]]; then - "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" -d "$BODY" "${REQUEST_URL}${ENDPOINT}" + "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" -d "$BODY" "${REQUEST_URL}${REQUEST_ENDPOINT}" else - "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" "${REQUEST_URL}${ENDPOINT}" + "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" "${REQUEST_URL}${REQUEST_ENDPOINT}" fi diff --git a/skills/sre/scripts/axiom-query b/skills/sre/scripts/axiom-query index a0471d3..54324ad 100755 --- a/skills/sre/scripts/axiom-query +++ b/skills/sre/scripts/axiom-query @@ -149,18 +149,19 @@ cleanup() { trap cleanup EXIT # Auto-resolve edge URL -QUERY_URL="$AXIOM_URL" +QUERY_PATH="/v1/datasets/_apl?format=tabular" DATASET=$(echo "$APL" | grep -oE "^\['[^']+'\]|^\[\"[^\"]+\"\]|^\[[a-zA-Z0-9_-]+\]" | head -1 | tr -d "[]'\"" || true) if [[ -n "$DATASET" ]]; then RESOLVED=$("$SCRIPT_DIR/resolve-url" "$DEPLOYMENT" "$DATASET" 2>/dev/null || true) - if [[ -n "$RESOLVED" ]]; then + if [[ -n "$RESOLVED" && "$RESOLVED" != "$AXIOM_URL" ]]; then QUERY_URL="$RESOLVED" + QUERY_PATH="/v1/query/_apl?format=tabular" fi fi # Execute query and pipe to formatter HTTP_CODE=$(curl -sS -o "$RESP_BODY" -D "$RESP_HEADERS" -w "%{http_code}" \ - -X POST "$QUERY_URL/v1/datasets/_apl?format=tabular" \ + -X POST "$QUERY_URL$QUERY_PATH" \ -H "Authorization: Bearer $AXIOM_TOKEN" \ -H "X-Axiom-Org-Id: $AXIOM_ORG_ID" \ -H "Content-Type: application/json" \ diff --git a/skills/sre/scripts/resolve-url b/skills/sre/scripts/resolve-url index da1079a..ba98f12 100755 --- a/skills/sre/scripts/resolve-url +++ b/skills/sre/scripts/resolve-url @@ -42,7 +42,7 @@ eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")" # Step 1: get dataset region REGION=$("$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X GET "${AXIOM_URL}/v1/datasets" \ - | jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .region // empty' 2>/dev/null) + | jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .edgeDeployment // .region // empty' 2>/dev/null) if [[ -z "$REGION" || "$REGION" == "null" ]]; then echo "$AXIOM_URL" From 4cbac0097624cfffbcbf32ad7a3e1c48d02dea8c Mon Sep 17 00:00:00 2001 From: Aisha Date: Tue, 10 Mar 2026 22:04:16 +0400 Subject: [PATCH 3/7] ops --- skills/sre/scripts/axiom-query | 1 + 1 file changed, 1 insertion(+) diff --git a/skills/sre/scripts/axiom-query b/skills/sre/scripts/axiom-query index 54324ad..552e7e5 100755 --- a/skills/sre/scripts/axiom-query +++ b/skills/sre/scripts/axiom-query @@ -149,6 +149,7 @@ cleanup() { trap cleanup EXIT # Auto-resolve edge URL +QUERY_URL="$AXIOM_URL" QUERY_PATH="/v1/datasets/_apl?format=tabular" DATASET=$(echo "$APL" | grep -oE "^\['[^']+'\]|^\[\"[^\"]+\"\]|^\[[a-zA-Z0-9_-]+\]" | head -1 | tr -d "[]'\"" || true) if [[ -n "$DATASET" ]]; then From 427b2c2efb6e29c187e2934bafcbd167de7c746a Mon Sep 17 00:00:00 2001 From: Aisha Date: Tue, 10 Mar 2026 22:12:50 +0400 Subject: [PATCH 4/7] rm unnecessary comments --- skills/sre/scripts/axiom-api | 1 - skills/sre/scripts/resolve-url | 1 - 2 files changed, 2 deletions(-) diff --git a/skills/sre/scripts/axiom-api b/skills/sre/scripts/axiom-api index e64ab55..27987e0 100755 --- a/skills/sre/scripts/axiom-api +++ b/skills/sre/scripts/axiom-api @@ -21,7 +21,6 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")" # Auto-resolve edge URL for query and ingest endpoints -# Edge uses /v1/query/_apl for queries (not /v1/datasets/_apl) REQUEST_URL="$AXIOM_URL" REQUEST_ENDPOINT="$ENDPOINT" case "$ENDPOINT" in diff --git a/skills/sre/scripts/resolve-url b/skills/sre/scripts/resolve-url index ba98f12..8d77d05 100755 --- a/skills/sre/scripts/resolve-url +++ b/skills/sre/scripts/resolve-url @@ -37,7 +37,6 @@ if [[ -f "$DATASET_CACHE" ]]; then fi fi -# Load config to get the base URL as fallback eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")" # Step 1: get dataset region From 237cc7ba82dc963ce9d20eff348849b456490f09 Mon Sep 17 00:00:00 2001 From: Aisha Date: Wed, 11 Mar 2026 13:19:31 +0400 Subject: [PATCH 5/7] use v2 dashboards endpoints --- skills/building-dashboards/scripts/axiom-api | 11 +++++------ .../scripts/dashboard-copy | 19 ++++++++++--------- .../scripts/dashboard-create | 10 ++++++---- .../scripts/dashboard-delete | 2 +- .../building-dashboards/scripts/dashboard-get | 2 +- .../scripts/dashboard-list | 4 ++-- .../scripts/dashboard-update | 8 +++++++- .../tests/test-script-output.sh | 16 ++++++++-------- 8 files changed, 40 insertions(+), 32 deletions(-) diff --git a/skills/building-dashboards/scripts/axiom-api b/skills/building-dashboards/scripts/axiom-api index c4ad00e..8a758a7 100755 --- a/skills/building-dashboards/scripts/axiom-api +++ b/skills/building-dashboards/scripts/axiom-api @@ -6,10 +6,10 @@ # Reads credentials from ~/.axiom.toml (shared with axiom-sre) # # Examples: -# axiom-api prod GET /internal/dashboards -# axiom-api prod GET /internal/dashboards/abc123 -# axiom-api prod POST /internal/dashboards '{"name":"Test",...}' -# axiom-api prod GET /v2/user +# axiom-api prod GET /dashboards +# axiom-api prod GET /dashboards/abc123 +# axiom-api prod POST /dashboards '{"name":"Test",...}' +# axiom-api prod GET /user set -euo pipefail @@ -59,8 +59,7 @@ if [[ -z "$URL" || -z "$TOKEN" || -z "$ORG_ID" ]]; then exit 1 fi -# Dashboard API uses app.* instead of api.* -API_URL="${URL/api./app.}/api" +API_URL="${URL%/}/v2" CURL_ARGS=( -s diff --git a/skills/building-dashboards/scripts/dashboard-copy b/skills/building-dashboards/scripts/dashboard-copy index 3c76e12..deb7321 100755 --- a/skills/building-dashboards/scripts/dashboard-copy +++ b/skills/building-dashboards/scripts/dashboard-copy @@ -21,25 +21,26 @@ if [[ -z "$DEPLOYMENT" || -z "$ID" ]]; then fi # Fetch original -ORIGINAL=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET "/internal/dashboards/$ID") +ORIGINAL=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET "/dashboards/uid/$ID") # Get original name if new name not provided if [[ -z "$NEW_NAME" ]]; then - ORIG_NAME=$(echo "$ORIGINAL" | jq -r '.name') + ORIG_NAME=$(echo "$ORIGINAL" | jq -r '.dashboard.name') NEW_NAME="${ORIG_NAME} (copy)" fi -# Strip server fields and set new name +# Strip server fields and set new name on the dashboard subobject BODY=$(echo "$ORIGINAL" | jq --arg name "$NEW_NAME" ' - del(.id, .version, .createdAt, .updatedAt, .createdBy, .updatedBy) | + .dashboard | + del(.id, .uid, .version, .createdAt, .updatedAt, .createdBy, .updatedBy) | .name = $name -') +' | jq '{dashboard: .}') -RESPONSE=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" POST "/internal/dashboards" "$BODY") +RESPONSE=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" POST "/dashboards" "$BODY") -# Print new ID and name -ID=$(echo "$RESPONSE" | jq -r '.id // empty') -NAME=$(echo "$RESPONSE" | jq -r '.name // empty') +# Print new UID and name +ID=$(echo "$RESPONSE" | jq -r '.dashboard.uid // empty') +NAME=$(echo "$RESPONSE" | jq -r '.dashboard.dashboard.name // empty') if [[ -n "$ID" ]]; then echo -e "${ID}\t${NAME}" diff --git a/skills/building-dashboards/scripts/dashboard-create b/skills/building-dashboards/scripts/dashboard-create index 372866a..00c8164 100755 --- a/skills/building-dashboards/scripts/dashboard-create +++ b/skills/building-dashboards/scripts/dashboard-create @@ -36,14 +36,16 @@ fi # Read, strip server-managed fields, and normalize layout for react-grid-layout BODY=$(jq -L "$SCRIPT_DIR" ' include "dashboard-normalize"; - del(.id, .version, .createdAt, .updatedAt, .createdBy, .updatedBy) | + del(.id, .uid, .version, .createdAt, .updatedAt, .createdBy, .updatedBy) | normalize_dashboard_layout ' "$JSON_FILE") -RESPONSE=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" POST "/internal/dashboards" "$BODY") +BODY=$(echo "$BODY" | jq '{dashboard: .}') -# Extract and print the new dashboard ID -ID=$(echo "$RESPONSE" | jq -r '.id // empty') +RESPONSE=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" POST "/dashboards" "$BODY") + +# Extract and print the new dashboard UID +ID=$(echo "$RESPONSE" | jq -r '.dashboard.uid // empty') if [[ -n "$ID" ]]; then echo "$ID" else diff --git a/skills/building-dashboards/scripts/dashboard-delete b/skills/building-dashboards/scripts/dashboard-delete index 1700e6b..7ae99ea 100755 --- a/skills/building-dashboards/scripts/dashboard-delete +++ b/skills/building-dashboards/scripts/dashboard-delete @@ -28,5 +28,5 @@ if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 0 fi -"$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" DELETE "/internal/dashboards/$ID" +"$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" DELETE "/dashboards/uid/$ID" echo "Deleted: $ID" diff --git a/skills/building-dashboards/scripts/dashboard-get b/skills/building-dashboards/scripts/dashboard-get index ecb1879..5e17186 100755 --- a/skills/building-dashboards/scripts/dashboard-get +++ b/skills/building-dashboards/scripts/dashboard-get @@ -19,4 +19,4 @@ if [[ -z "$DEPLOYMENT" || -z "$ID" ]]; then exit 1 fi -"$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET "/internal/dashboards/$ID" | jq . +"$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET "/dashboards/uid/$ID" | jq '.dashboard' diff --git a/skills/building-dashboards/scripts/dashboard-list b/skills/building-dashboards/scripts/dashboard-list index e78dbfb..9e37d40 100755 --- a/skills/building-dashboards/scripts/dashboard-list +++ b/skills/building-dashboards/scripts/dashboard-list @@ -19,10 +19,10 @@ if [[ -z "$DEPLOYMENT" ]]; then exit 1 fi -RESPONSE=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET "/internal/dashboards?limit=1000") +RESPONSE=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET "/dashboards?limit=1000") if [[ "$FORMAT" == "--json" ]]; then echo "$RESPONSE" | jq . else - echo "$RESPONSE" | jq -r '.[] | [.id, .name] | @tsv' + echo "$RESPONSE" | jq -r '.[] | [.uid, .dashboard.name] | @tsv' fi diff --git a/skills/building-dashboards/scripts/dashboard-update b/skills/building-dashboards/scripts/dashboard-update index 54e45e0..12342a3 100755 --- a/skills/building-dashboards/scripts/dashboard-update +++ b/skills/building-dashboards/scripts/dashboard-update @@ -49,6 +49,12 @@ if [[ -z "$VERSION" ]]; then exit 1 fi -RESPONSE=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" PUT "/internal/dashboards/$ID" "$BODY") +# Wrap body in v2 envelope: {dashboard: {...}, version: N} +# Version must be a numeric int64. jq loses precision on large integers, +# so we inject it via string substitution. +DASHBOARD=$(echo "$BODY" | jq 'del(.version)') +BODY="{\"dashboard\":${DASHBOARD},\"version\":${VERSION}}" + +RESPONSE=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" PUT "/dashboards/uid/$ID" "$BODY") echo "$RESPONSE" | jq . diff --git a/skills/building-dashboards/tests/test-script-output.sh b/skills/building-dashboards/tests/test-script-output.sh index ff21916..5b294db 100755 --- a/skills/building-dashboards/tests/test-script-output.sh +++ b/skills/building-dashboards/tests/test-script-output.sh @@ -64,11 +64,11 @@ METHOD="${2:-}" PATH_="${3:-}" case "$METHOD:$PATH_" in - "POST:/internal/dashboards") - echo '{"id":"created-id"}' + "POST:/dashboards") + echo '{"status":"created","dashboard":{"uid":"created-uid","id":"created-id","version":1,"dashboard":{"name":"Test Dashboard"},"createdAt":"2026-02-01T10:00:00Z","updatedAt":"2026-02-01T10:00:00Z","createdBy":"alice@example.com","updatedBy":"alice@example.com"}}' ;; - "PUT:/internal/dashboards/dashboard-root-id") - echo '{"id":"dashboard-root-id","updated":true}' + "PUT:/dashboards/uid/dashboard-root-id") + echo '{"status":"updated","dashboard":{"uid":"dashboard-root-id","id":"dashboard-root-id","version":2,"dashboard":{"name":"Test Dashboard","updated":true},"createdAt":"2026-02-01T10:00:00Z","updatedAt":"2026-02-02T11:00:00Z","createdBy":"alice@example.com","updatedBy":"bob@example.com"}}' ;; *) echo "Unexpected call: $METHOD $PATH_" >&2 @@ -83,14 +83,14 @@ echo "Script Stdout Contract" echo "======================" create_out=$("$TMPDIR/dashboard-create" prod "$TMPDIR/input.json") -if [[ "$create_out" == "created-id" ]]; then - ok "dashboard-create outputs only dashboard ID" +if [[ "$create_out" == "created-uid" ]]; then + ok "dashboard-create outputs only dashboard UID" else - fail "dashboard-create outputs only dashboard ID" "got: $create_out" + fail "dashboard-create outputs only dashboard UID" "got: $create_out" fi update_out=$("$TMPDIR/dashboard-update" prod dashboard-root-id "$TMPDIR/input.json") -if echo "$update_out" | jq -e '.id == "dashboard-root-id" and .updated == true' > /dev/null 2>&1; then +if echo "$update_out" | jq -e '.dashboard.uid == "dashboard-root-id" and .dashboard.dashboard.updated == true' > /dev/null 2>&1; then ok "dashboard-update outputs valid JSON only" else fail "dashboard-update outputs valid JSON only" "got: $update_out" From 12f9d676fbf5142ebcbefd844a0ca5ea5f97dc52 Mon Sep 17 00:00:00 2001 From: Aisha Date: Wed, 11 Mar 2026 17:18:03 +0400 Subject: [PATCH 6/7] revert sre files to sync with gilfoyle --- skills/sre/reference/api-capabilities.md | 9 +-- skills/sre/reference/axiom.md | 9 +-- skills/sre/scripts/axiom-api | 28 +------- skills/sre/scripts/axiom-link | 2 +- skills/sre/scripts/axiom-query | 14 +--- skills/sre/scripts/resolve-url | 88 ------------------------ 6 files changed, 14 insertions(+), 136 deletions(-) delete mode 100755 skills/sre/scripts/resolve-url diff --git a/skills/sre/reference/api-capabilities.md b/skills/sre/reference/api-capabilities.md index 2fbae87..ff08146 100644 --- a/skills/sre/reference/api-capabilities.md +++ b/skills/sre/reference/api-capabilities.md @@ -1,12 +1,13 @@ # Axiom API Capabilities -Summary of all operations available via Axiom API. +Summary of all operations available via Axiom API with a personal access token (PAT). -**Base URL:** `https://api.axiom.co` (for management endpoints) -**Query & Ingest URL:** Auto-resolved per dataset via `scripts/resolve-url` +**Base URL:** `https://api.axiom.co` (for all endpoints except ingestion) +**Ingest URL:** Use edge deployment domain (e.g., `https://us-east-1.aws.edge.axiom.co`) **Authentication:** -- `Authorization: Bearer $API_TOKEN` — use an advanced API token with minimal privileges +- PAT: `Authorization: Bearer $PAT` + `x-axiom-org-id: $ORG_ID` +- API Token: `Authorization: Bearer $API_TOKEN` --- diff --git a/skills/sre/reference/axiom.md b/skills/sre/reference/axiom.md index 5b78cd0..db9b12e 100644 --- a/skills/sre/reference/axiom.md +++ b/skills/sre/reference/axiom.md @@ -1,12 +1,13 @@ # Axiom API Capabilities -Summary of all operations available via Axiom API. +Summary of all operations available via Axiom API with a personal access token (PAT). -**Base URL:** `https://api.axiom.co` (for management endpoints) -**Query & Ingest URL:** Auto-resolved per dataset via `scripts/resolve-url` +**Base URL:** `https://api.axiom.co` (for all endpoints except ingestion) +**Ingest URL:** Use edge deployment domain (e.g., `https://us-east-1.aws.edge.axiom.co`) **Authentication:** -- `Authorization: Bearer $API_TOKEN` — use an advanced API token with minimal privileges +- PAT: `Authorization: Bearer $PAT` + `x-axiom-org-id: $ORG_ID` +- API Token: `Authorization: Bearer $API_TOKEN` --- diff --git a/skills/sre/scripts/axiom-api b/skills/sre/scripts/axiom-api index 27987e0..f4bf71e 100755 --- a/skills/sre/scripts/axiom-api +++ b/skills/sre/scripts/axiom-api @@ -20,32 +20,8 @@ fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")" -# Auto-resolve edge URL for query and ingest endpoints -REQUEST_URL="$AXIOM_URL" -REQUEST_ENDPOINT="$ENDPOINT" -case "$ENDPOINT" in - /v1/datasets/_apl*|/v1/ingest/*) - DATASET="" - if [[ "$ENDPOINT" == /v1/ingest/* ]]; then - DATASET="${ENDPOINT#/v1/ingest/}" - DATASET="${DATASET%%[?/]*}" - elif [[ -n "$BODY" ]]; then - DATASET=$(echo "$BODY" | jq -r '.apl // empty' 2>/dev/null | grep -oE "^\['[^']+'\]|^\[\"[^\"]+\"\]|^\[[a-zA-Z0-9_-]+\]" | head -1 | tr -d "[]'\"" || true) - fi - if [[ -n "$DATASET" ]]; then - RESOLVED=$("$SCRIPT_DIR/resolve-url" "$DEPLOYMENT" "$DATASET" 2>/dev/null || true) - if [[ -n "$RESOLVED" && "$RESOLVED" != "$AXIOM_URL" ]]; then - REQUEST_URL="$RESOLVED" - if [[ "$ENDPOINT" == /v1/datasets/_apl* ]]; then - REQUEST_ENDPOINT="/v1/query/_apl${ENDPOINT#/v1/datasets/_apl}" - fi - fi - fi - ;; -esac - if [[ -n "$BODY" ]]; then - "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" -d "$BODY" "${REQUEST_URL}${REQUEST_ENDPOINT}" + "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" -d "$BODY" "${AXIOM_URL}${ENDPOINT}" else - "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" "${REQUEST_URL}${REQUEST_ENDPOINT}" + "$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X "$METHOD" "${AXIOM_URL}${ENDPOINT}" fi diff --git a/skills/sre/scripts/axiom-link b/skills/sre/scripts/axiom-link index 25bc9cc..266ee62 100755 --- a/skills/sre/scripts/axiom-link +++ b/skills/sre/scripts/axiom-link @@ -37,10 +37,10 @@ fi # Derive web UI URL from configured API URL # Replace "api." with "app." in the domain # Examples: -# https://api.axiom.co → https://app.axiom.co # https://api.staging.axiom.co → https://app.staging.axiom.co # https://api.dev.axiom.co → https://app.dev.axiom.co # https://cloud.axiom.co → https://app.axiom.co +# https://api.axiom.co → https://app.axiom.co if [[ "$URL" == *"cloud.axiom.co"* ]]; then BASE_URL="https://app.axiom.co" elif [[ "$URL" == https://api.* ]]; then diff --git a/skills/sre/scripts/axiom-query b/skills/sre/scripts/axiom-query index 552e7e5..c15f737 100755 --- a/skills/sre/scripts/axiom-query +++ b/skills/sre/scripts/axiom-query @@ -148,21 +148,9 @@ cleanup() { } trap cleanup EXIT -# Auto-resolve edge URL -QUERY_URL="$AXIOM_URL" -QUERY_PATH="/v1/datasets/_apl?format=tabular" -DATASET=$(echo "$APL" | grep -oE "^\['[^']+'\]|^\[\"[^\"]+\"\]|^\[[a-zA-Z0-9_-]+\]" | head -1 | tr -d "[]'\"" || true) -if [[ -n "$DATASET" ]]; then - RESOLVED=$("$SCRIPT_DIR/resolve-url" "$DEPLOYMENT" "$DATASET" 2>/dev/null || true) - if [[ -n "$RESOLVED" && "$RESOLVED" != "$AXIOM_URL" ]]; then - QUERY_URL="$RESOLVED" - QUERY_PATH="/v1/query/_apl?format=tabular" - fi -fi - # Execute query and pipe to formatter HTTP_CODE=$(curl -sS -o "$RESP_BODY" -D "$RESP_HEADERS" -w "%{http_code}" \ - -X POST "$QUERY_URL$QUERY_PATH" \ + -X POST "$AXIOM_URL/v1/datasets/_apl?format=tabular" \ -H "Authorization: Bearer $AXIOM_TOKEN" \ -H "X-Axiom-Org-Id: $AXIOM_ORG_ID" \ -H "Content-Type: application/json" \ diff --git a/skills/sre/scripts/resolve-url b/skills/sre/scripts/resolve-url deleted file mode 100755 index 8d77d05..0000000 --- a/skills/sre/scripts/resolve-url +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash -# resolve-url: Resolve the regional edge URL for a dataset -# -# Usage: resolve-url -# -# Two-step resolution: -# 1. GET /v1/datasets → find dataset's region (e.g. cloud.us-east-1.aws) -# 2. GET /api/internal/regions/axiom → map region to edge domain -# -# Both steps are cached to avoid repeated API calls. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -DEPLOYMENT="${1:-}" -DATASET="${2:-}" - -if [[ -z "$DEPLOYMENT" || -z "$DATASET" ]]; then - echo "Usage: resolve-url " >&2 - exit 1 -fi - -CACHE_DIR="${TMPDIR:-/tmp}/axiom-edge-cache" - -# Check dataset edge URL cache (valid for 1 hour) -DATASET_CACHE="$CACHE_DIR/edge__${DEPLOYMENT}__${DATASET}" -if [[ -f "$DATASET_CACHE" ]]; then - if [[ "$(uname)" == "Darwin" ]]; then - AGE=$(( $(date +%s) - $(stat -f %m "$DATASET_CACHE") )) - else - AGE=$(( $(date +%s) - $(stat -c %Y "$DATASET_CACHE") )) - fi - if [[ $AGE -lt 3600 ]]; then - cat "$DATASET_CACHE" - exit 0 - fi -fi - -eval "$("$SCRIPT_DIR/config" axiom "$DEPLOYMENT")" - -# Step 1: get dataset region -REGION=$("$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X GET "${AXIOM_URL}/v1/datasets" \ - | jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .edgeDeployment // .region // empty' 2>/dev/null) - -if [[ -z "$REGION" || "$REGION" == "null" ]]; then - echo "$AXIOM_URL" - exit 0 -fi - -# Step 2: look up edge domain from regions API (cached 24h per deployment) -REGIONS_CACHE="$CACHE_DIR/regions__${DEPLOYMENT}" -REGIONS_JSON="" -if [[ -f "$REGIONS_CACHE" ]]; then - if [[ "$(uname)" == "Darwin" ]]; then - AGE=$(( $(date +%s) - $(stat -f %m "$REGIONS_CACHE") )) - else - AGE=$(( $(date +%s) - $(stat -c %Y "$REGIONS_CACHE") )) - fi - if [[ $AGE -lt 86400 ]]; then - REGIONS_JSON=$(cat "$REGIONS_CACHE") - fi -fi - -if [[ -z "$REGIONS_JSON" ]]; then - APP_URL="${AXIOM_URL/api./app.}" - REGIONS_JSON=$("$SCRIPT_DIR/curl-auth" axiom "$DEPLOYMENT" -X GET "${APP_URL}/api/internal/regions/axiom" 2>/dev/null) || true - if [[ -n "$REGIONS_JSON" ]]; then - mkdir -p "$CACHE_DIR" - echo "$REGIONS_JSON" > "$REGIONS_CACHE" - fi -fi - -EDGE_DOMAIN="" -if [[ -n "$REGIONS_JSON" ]]; then - EDGE_DOMAIN=$(echo "$REGIONS_JSON" | jq -r --arg region "$REGION" '.axiom[] | select(.id == $region) | .domain // empty' 2>/dev/null) -fi - -if [[ -z "$EDGE_DOMAIN" ]]; then - echo "$AXIOM_URL" - exit 0 -fi - -# Cache the resolved edge URL -mkdir -p "$CACHE_DIR" -echo "$EDGE_DOMAIN" > "$DATASET_CACHE" - -echo "$EDGE_DOMAIN" From 899133c570db5639586b05b3ff686ecce3ba3c70 Mon Sep 17 00:00:00 2001 From: Aisha Date: Tue, 17 Mar 2026 13:54:06 +0400 Subject: [PATCH 7/7] revert metrics --- skills/query-metrics/scripts/resolve-url | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/skills/query-metrics/scripts/resolve-url b/skills/query-metrics/scripts/resolve-url index 3e47368..bfcde3c 100755 --- a/skills/query-metrics/scripts/resolve-url +++ b/skills/query-metrics/scripts/resolve-url @@ -3,10 +3,10 @@ # # Usage: resolve-url # -# Fetches the dataset's region from the Axiom API and maps it to the +# Fetches the dataset's edgeDeployment from the Axiom API and maps it to the # correct edge URL. Prints the URL to stdout. # -# Region mapping: +# Edge deployment mapping: # cloud.us-east-1.aws → https://us-east-1.aws.edge.axiom.co # cloud.eu-central-1.aws → https://eu-central-1.aws.edge.axiom.co # (null/empty) → falls back to deployment URL from config @@ -35,14 +35,14 @@ extract_value() { FALLBACK_URL=$(extract_value "url") -REGION=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET /v1/datasets \ - | jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .edgeDeployment // .region // empty') +EDGE_DEPLOYMENT=$("$SCRIPT_DIR/axiom-api" "$DEPLOYMENT" GET /v1/datasets \ + | jq -r --arg name "$DATASET" '.[] | select(.name == $name) | .edgeDeployment // empty') -if [[ -z "$REGION" || "$REGION" == "null" ]]; then +if [[ -z "$EDGE_DEPLOYMENT" || "$EDGE_DEPLOYMENT" == "null" ]]; then echo "$FALLBACK_URL" exit 0 fi # cloud.us-east-1.aws → https://us-east-1.aws.edge.axiom.co -EDGE_HOST="${REGION#cloud.}" +EDGE_HOST="${EDGE_DEPLOYMENT#cloud.}" echo "https://${EDGE_HOST}.edge.axiom.co"