Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 61 additions & 21 deletions hack/install-ax.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ function usage() {
echo "Options:"
echo " --deploy-ax-server Build images and deploy AX server and components"
echo " --delete-ax-server Delete AX server and components, preserving the event-log database"
echo " --deploy-postgres With --deploy-ax-server: also deploy a bundled Postgres for testing (default: connect to an existing Postgres via AX_EVENTLOG_DSN)"
echo " -h, --help Show this help message"
}

Expand Down Expand Up @@ -196,6 +197,11 @@ deploy_ax_server() {
echo "Error: AX_SNAPSHOTS_BUCKET environment variable must be set" >&2
exit 1
fi
# The default (external Postgres) path needs a DSN; fail fast before building.
if [[ "${DEPLOY_POSTGRES}" != "true" && -z "${AX_EVENTLOG_DSN:-}" ]]; then
echo "Error: AX_EVENTLOG_DSN must be set to your Postgres DSN, or pass --deploy-postgres to deploy a bundled test Postgres." >&2
exit 1
fi

echo "Using GCS Bucket: ${AX_SNAPSHOTS_BUCKET}"

Expand All @@ -204,36 +210,61 @@ deploy_ax_server() {
ax_image=$(build_ax_image)
ateom_image=$(build_ateom_image)

# Resolve a stable Postgres password for the event log.
local pg_password="${POSTGRES_PASSWORD:-}"
local existing_pw
existing_pw="$(run_kubectl -n ax get secret ax-eventlog-postgres -o go-template='{{.data.password | base64decode}}' 2>/dev/null || true)"
if [[ -n "${existing_pw}" ]]; then
pg_password="${existing_pw}"
elif [[ -z "${pg_password}" ]]; then
pg_password="$(openssl rand -hex 16)"
# Resolve the event-log Postgres DSN. By default ax-server connects to an
# existing Postgres via AX_EVENTLOG_DSN; --deploy-postgres creates a bundled
# Postgres in-cluster (for testing) and derives the DSN from it.
local pg_dsn pg_password=""
if [[ "${DEPLOY_POSTGRES}" == "true" ]]; then
# Reuse the existing bundled-Postgres password if present, else POSTGRES_PASSWORD,
# else generate one.
local existing_pw
existing_pw="$(run_kubectl -n ax get secret ax-eventlog-postgres -o go-template='{{.data.password | base64decode}}' 2>/dev/null || true)"
if [[ -n "${existing_pw}" ]]; then
pg_password="${existing_pw}"
else
pg_password="${POSTGRES_PASSWORD:-$(openssl rand -hex 16)}"
fi
pg_dsn="postgres://axuser:${pg_password}@ax-eventlog-postgres.ax.svc:5432/axeventlog?sslmode=disable"
else
pg_dsn="${AX_EVENTLOG_DSN}"
echo "Using existing Postgres via AX_EVENTLOG_DSN." >&2
fi

# Render the manifest and apply it.
if ! sed -e "s|\${GEMINI_API_KEY}|${GEMINI_API_KEY}|g" \
-e "s|\${AX_SNAPSHOTS_BUCKET}|${AX_SNAPSHOTS_BUCKET}|g" \
-e "s|\${AX_IMAGE}|${ax_image}|g" \
-e "s|\${ATEOM_IMAGE}|${ateom_image}|g" \
-e "s|\${POSTGRES_PASSWORD}|${pg_password}|g" \
manifests/ax-deployment.yaml \
| run_kubectl apply -f -; then
# Common substitutions applied to every rendered manifest.
local render_sed=(
-e "s|\${GEMINI_API_KEY}|${GEMINI_API_KEY}|g"
-e "s|\${AX_SNAPSHOTS_BUCKET}|${AX_SNAPSHOTS_BUCKET}|g"
-e "s|\${AX_IMAGE}|${ax_image}|g"
-e "s|\${ATEOM_IMAGE}|${ateom_image}|g"
)

# Render and apply the core manifest (namespace, harnesses, ax-server, ConfigMap).
if ! sed "${render_sed[@]}" manifests/ax-deployment.yaml | run_kubectl apply -f -; then
echo >&2
echo "Error: cluster rejected the manifest. An \"unknown field\" error usually means the" >&2
echo "cluster's substrate is incompatible with AX's go.mod pin — see" >&2
echo "manifests/README.md (\"Substrate compatibility\")." >&2
exit 1
fi

# Wait for the event-log Postgres to be ready before ax-server relies on it.
log_step "wait for statefulset/ax-eventlog-postgres to be ready"
wait_with_spinner "waiting for postgres (timeout ${AX_WAIT_TIMEOUT:-5m})" \
run_kubectl -n ax rollout status statefulset/ax-eventlog-postgres \
--timeout="${AX_WAIT_TIMEOUT:-5m}"
# Create/update the event-log Secret with the DSN (and, for the bundled Postgres,
# its password). ax-server reads AX_EVENTLOG_DSN from this Secret's dsn key.
local secret_args=(--from-literal=dsn="${pg_dsn}")
if [[ "${DEPLOY_POSTGRES}" == "true" ]]; then
secret_args+=(--from-literal=password="${pg_password}")
fi
run_kubectl -n ax create secret generic ax-eventlog-postgres "${secret_args[@]}" \
--dry-run=client -o yaml | run_kubectl apply -f -

# With --deploy-postgres, create the bundled Postgres and wait for it to be
# ready before ax-server relies on it.
if [[ "${DEPLOY_POSTGRES}" == "true" ]]; then
run_kubectl apply -f manifests/ax-postgres.yaml
log_step "wait for statefulset/ax-eventlog-postgres to be ready"
wait_with_spinner "waiting for postgres (timeout ${AX_WAIT_TIMEOUT:-5m})" \
run_kubectl -n ax rollout status statefulset/ax-eventlog-postgres \
--timeout="${AX_WAIT_TIMEOUT:-5m}"
fi

# Wait for the antigravity ActorTemplate's golden snapshot to be ready.
log_step "wait for actortemplate/ax-harness-template to be Ready"
Expand Down Expand Up @@ -265,20 +296,29 @@ if [ "$#" -eq 0 ]; then
exit 1
fi

# Event-log Postgres: by default ax-server connects to an existing Postgres via
# the AX_EVENTLOG_DSN env var. --deploy-postgres additionally creates a bundled
# Postgres in-cluster (for testing on Substrate).
DEPLOY_POSTGRES=false

# If -h or --help appears anywhere in the command line, print the usage and exit.
for arg in "$@"; do
case "$arg" in
-h|--help)
usage
exit 0
;;
--deploy-postgres)
DEPLOY_POSTGRES=true
;;
esac
done

while [[ "$#" -gt 0 ]]; do
case $1 in
--deploy-ax-server) deploy_ax_server ;;
--delete-ax-server) delete_ax_server ;;
--deploy-postgres) ;; # resolved in the pre-scan above
*)
echo "Error: unknown option: $1" >&2
echo ""
Expand Down
17 changes: 16 additions & 1 deletion manifests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,27 @@ gcloud auth configure-docker # set up the gcr.io credential helper

#### Deploy

The event log is stored in Postgres. By default ax-server connects to an
**existing** Postgres that you provide via the `AX_EVENTLOG_DSN` env var (bring your own database). Pass `--deploy-postgres` to also
create a **bundled** Postgres in-cluster instead (for testing).

```bash
export PROJECT_ID="ax-substrate" # Your GCP project ID
export GEMINI_API_KEY="your-api-key"
export AX_SNAPSHOTS_BUCKET="snapshot-substrate-test-$PROJECT_ID"

# Connect to your existing Postgres:
export AX_EVENTLOG_DSN="postgres://user:pass@host:5432/db?sslmode=require"
./hack/install-ax.sh --deploy-ax-server

# Or deploy a bundled Postgres for testing:
./hack/install-ax.sh --deploy-ax-server --deploy-postgres
```

The bundled Postgres uses an auto-generated password. To get its DSN:

```bash
kubectl get secret ax-eventlog-postgres -n ax -o go-template='{{.data.dsn | base64decode}}'
```

### 2. Port-Forward Services
Expand Down Expand Up @@ -114,7 +129,7 @@ Use the **`kubectl ate`** CLI tool to inspect the live states of
active actors and allocated standby worker pool instances:

```bash
kubectl ate get actors
kubectl ate get actors -a ax

kubectl ate get workers
```
Expand Down
80 changes: 0 additions & 80 deletions manifests/ax-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,86 +71,6 @@ spec:
location: gs://${AX_SNAPSHOTS_BUCKET}/antigravity/
---

# ---------------------------------------------------------------------------
# Event log storage (PostgreSQL)
# ---------------------------------------------------------------------------
apiVersion: v1
kind: Service
metadata:
name: ax-eventlog-postgres
namespace: ax
labels:
app: ax-eventlog-postgres
spec:
selector:
app: ax-eventlog-postgres
ports:
- port: 5432
targetPort: 5432
---
apiVersion: v1
kind: Secret
metadata:
name: ax-eventlog-postgres
namespace: ax
type: Opaque
stringData:
password: "${POSTGRES_PASSWORD}"
dsn: "postgres://axuser:${POSTGRES_PASSWORD}@ax-eventlog-postgres.ax.svc:5432/axeventlog?sslmode=disable"
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: ax-eventlog-postgres
namespace: ax
labels:
app: ax-eventlog-postgres
spec:
serviceName: ax-eventlog-postgres
replicas: 1
selector:
matchLabels:
app: ax-eventlog-postgres
template:
metadata:
labels:
app: ax-eventlog-postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: axeventlog
- name: POSTGRES_USER
value: axuser
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: ax-eventlog-postgres
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
readinessProbe:
exec:
command: ["pg_isready", "-U", "axuser", "-d", "axeventlog"]
initialDelaySeconds: 5
periodSeconds: 5
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---

# ---------------------------------------------------------------------------
# AX Server
# ---------------------------------------------------------------------------
Expand Down
87 changes: 87 additions & 0 deletions manifests/ax-postgres.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# ---------------------------------------------------------------------------
# Event log storage (PostgreSQL)
#
# Applied by hack/install-ax.sh only when --deploy-postgres is passed. By default
# ax-server connects to an existing Postgres via AX_EVENTLOG_DSN and these
# resources are not deployed. The ax-eventlog-postgres Secret (holding the
# password used below and the DSN) is created by install-ax.sh.
# ---------------------------------------------------------------------------
apiVersion: v1
kind: Service
metadata:
name: ax-eventlog-postgres
namespace: ax
labels:
app: ax-eventlog-postgres
spec:
selector:
app: ax-eventlog-postgres
ports:
- port: 5432
targetPort: 5432
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: ax-eventlog-postgres
namespace: ax
labels:
app: ax-eventlog-postgres
spec:
serviceName: ax-eventlog-postgres
replicas: 1
selector:
matchLabels:
app: ax-eventlog-postgres
template:
metadata:
labels:
app: ax-eventlog-postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: axeventlog
- name: POSTGRES_USER
value: axuser
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: ax-eventlog-postgres
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
readinessProbe:
exec:
command: ["pg_isready", "-U", "axuser", "-d", "axeventlog"]
initialDelaySeconds: 5
periodSeconds: 5
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
Loading