Skip to content

Verify the installation

Run these after the install and after every upgrade. Each check says what a pass looks like. The last one, NetworkPolicy, is the one a clean install cannot prove on its own.

On an operator install, the resource reports every component available:

kubectl -n olympus get olympuses.olympus.olympusx.ai olympus
# NAME VERSION COMPONENTS READY AGE
# olympus 1.1.0 11/11 True 20m

The denominator is however many components your resource turns on: nine with neither the identity service nor the guardrails service, eleven with both.

On either path:

kubectl -n olympus get pods
kubectl -n olympus rollout status deploy/olympus-control-plane
kubectl -n olympus rollout status deploy/olympus-gateway

Every pod is Running and Ready, and both rollouts report successfully rolled out.

kubectl -n olympus logs deploy/olympus-control-plane -c migrate | tail -3
# {"time":"…","level":"INFO","msg":"migrations complete","applied":…,"already_applied":…}

Several pods run the same migration step and exactly one applies the schema, so one pod reports a count under applied and the others under already_applied. Either line means the schema is current. The control plane reports not ready until the schema matches its version.

The console answers, and reaches the control plane

Section titled “The console answers, and reaches the control plane”
kubectl -n olympus port-forward svc/olympus-studio 8080:8080

In a second terminal:

curl -s localhost:8080/api/v1/ping
# {"env":"prod","pong":"olympus"}

The request goes to the console, which forwards /api/ to the control plane, so the answer proves both and the link between them.

Through the published hostname, the console sends its security headers:

curl -sI https://<console-host>/ | grep -i -E 'strict-transport|content-security'
# strict-transport-security: max-age=31536000; includeSubDomains
# content-security-policy: default-src 'self'; script-src 'self' 'sha256-…'; …

The policy names the identity provider’s origin for sign-in, derived from the issuer, and forbids framing the console. If curl rejects the certificate, this machine does not trust it, and browsers that do not trust it will warn the same way.

kubectl get --raw /api/v1/namespaces/olympus/services/olympus-control-plane:http/proxy/readyz
# {"status":"ready"}
curl -s https://<gateway-host>/v1/chat/completions \
-H 'content-type: application/json' -d '{"model":"x","messages":[]}'
# {"error":{"message":"provide an Olympus API key as x-api-key or Authorization: Bearer","type":"authentication_error","code":"missing_credentials","param":null}}

A refusal naming the missing key is the pass. A 404 on every request means the gateway has not received its configuration from the control plane (Troubleshooting).

Open https://<console-host> and sign in (First sign-in). If nobody can sign in while every component is healthy, the issuer is wrong or unreachable:

kubectl -n olympus logs deploy/olympus-control-plane | grep -i "identity provider"

identity provider not reachable yet means the control plane cannot fetch the issuer’s discovery document.

Invite yourself to a tenant (First sign-in). The console says Invitation sent, and an email titled “Your Olympusx AI account is ready” arrives from the sender address you configured, with a link on <console-host>.

If you turned it on:

kubectl -n olympus rollout status deploy/olympus-guardrails
# deployment "olympus-guardrails" successfully rolled out

In the console, Infrastructure › System health shows Guardrails as Healthy. If you left it off, the control plane’s log opens with GUARDRAILS ARE DISABLED: prompts and completions pass through uninspected. In an environment carrying customer data, that line is a finding.

If you turned monitoring on:

kubectl -n olympus get servicemonitor

Two ServiceMonitors exist. Then confirm in Prometheus that their targets are up: an object that exists proves nothing about scraping. No targets almost always means a selector label (Configuration). On OpenShift, a cluster administrator must have turned on user-workload monitoring.

The control plane’s internal listeners have no authentication by design; a NetworkPolicy admits only the gateway’s pods. Whether that policy does anything depends on your CNI, and the API server accepts it either way. Measure it.

Probe a closed port from a pod that is not the gateway:

kubectl -n olympus run probe --rm -i --restart=Never --image=curlimages/curl:8.10.1 -- \
curl -s -o /dev/null -w '%{http_code}\n' --max-time 6 \
http://olympus-control-plane:8084/internal/authorize
# 000

Then show the same probe works where the policy leaves the port open:

kubectl -n olympus run probe --rm -i --restart=Never --image=curlimages/curl:8.10.1 -- \
curl -s -o /dev/null -w '%{http_code}\n' --max-time 6 \
http://olympus-control-plane:8080/healthz
# 200

Read the pair together:

  • Any HTTP status on the first probe (200, 400, 401) is conclusive and bad: the policy is not enforced, and the internal ports are open to everything in the namespace.
  • 000 on the first and 200 on the second is enforcement.
  • 000 on both means the probe never worked (DNS, scheduling, the image), and you have learned nothing.

Any image with curl works; on an air-gapped cluster, use one from your mirror.

From a tenant’s project namespace, connections to these should time out rather than connect:

From a tenant namespace, to Expect
The control plane’s internal ports 8083, 8084, 8085 Timeout
The control plane’s metrics port 8086 Timeout, unless the namespace is an allowed scraper
The platform database on 5432 Timeout
The guardrails service, document converter, object store and tracing store Timeout
The gateway on 10000 Connects: it is the inference API

A refusal (connection refused) means nothing was listening and proves nothing; a timeout is the policy dropping the packet. Record the results. If your CNI does not enforce policy, record that in your risk register rather than assuming the chart protected you.