The operator, recorded
15 sessions, recorded at the terminal against a four-node kind cluster with the operator installed from its chart. Each one is checked while it runs: a recording is published only if every condition it claims held on the live cluster. Open one to read the session in full; Play types it out where it stands.
- Kubernetes1.37.0
- Operatore41a04412bb1
- Ptahv0.18.0
- Executorsha256:9f8797986124
- Recorded2026-11-06
- Checks held191
- Runs15
These sessions were recorded against Ptah v0.18.0. The supported executor is now v0.23.0, so read them as evidence about the operator's behavior rather than as a check that these commands still run unchanged today.
A replay of a verified run, not a live cluster. Nothing on this page talks to anything.
# The lab is one cluster, built from the versions this repository declares.$ demo/bin/lab versionskubernetes 1.37.0kind v0.33.0operator e41a04412bb12281b068f8b6bc1f7f83025522aaexecutor e2e-registry.demo.svc.cluster.local:5000/ptah-executor@sha256:9f8797986124add44d0232a17cd17e6f03cfec76b1711efc53c169483b7b4303ptah v0.18.0 # An install that finished, not one that started. The rollout is complete.$ kubectl -n "$OPERATOR_NAMESPACE" rollout status deployment "$CONTROLLER" --timeout=3mdeployment "ptah-operator" successfully rolled out # Two replicas, one leader, and every image a digest, so one exact build runs.$ kubectl -n "$OPERATOR_NAMESPACE" get deployment -o wideNAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTORptah-operator-cert-rotator 1/1 1 1 13m certificate-rotator e2e-registry.demo.svc.cluster.local:5000/ptah-operator@sha256:95a15ea10a9e8985748269943615e7cef8b99e02d78238ffcf48809c8a028fe1 app.kubernetes.io/component=certificate-rotation,app.kubernetes.io/instance=ptah,app.kubernetes.io/name=ptah-operatorptah-operator 2/2 2 2 13m manager e2e-registry.demo.svc.cluster.local:5000/ptah-operator@sha256:95a15ea10a9e8985748269943615e7cef8b99e02d78238ffcf48809c8a028fe1 app.kubernetes.io/component=controller,app.kubernetes.io/instance=ptah,app.kubernetes.io/name=ptah-operator # The kinds the operator serves. A schema, its plan, and the approval that lets it run.$ kubectl api-resources --api-group=operator.ptah.runNAME SHORTNAMES APIVERSION NAMESPACED KINDptahmigrationapprovals ptahmapprove operator.ptah.run/v1alpha1 true PtahMigrationApprovalptahmigrationplans ptahmplan operator.ptah.run/v1alpha1 true PtahMigrationPlanptahmigrationrunacknowledgments ptahmack operator.ptah.run/v1alpha1 true PtahMigrationRunAcknowledgmentptahmigrations ptahm operator.ptah.run/v1alpha1 true PtahMigrationptahrealms ptahr operator.ptah.run/v1alpha1 false PtahRealmptahresultrecords ptahresult operator.ptah.run/v1alpha1 true PtahResultRecordptahschemaapprovals ptahapprove operator.ptah.run/v1alpha1 true PtahSchemaApprovalptahschemaplanchunks ptahchunk operator.ptah.run/v1alpha1 true PtahSchemaPlanChunkptahschemaplans ptahplan operator.ptah.run/v1alpha1 true PtahSchemaPlanptahschemas ptahs operator.ptah.run/v1alpha1 true PtahSchema # Each of those is served once its CRD is Established.$ kubectl wait --for=condition=Established --timeout=1m \ crd/ptahschemas.operator.ptah.run crd/ptahschemaplans.operator.ptah.run crd/ptahschemaapprovals.operator.ptah.runcustomresourcedefinition.apiextensions.k8s.io/ptahschemas.operator.ptah.run condition metcustomresourcedefinition.apiextensions.k8s.io/ptahschemaplans.operator.ptah.run condition metcustomresourcedefinition.apiextensions.k8s.io/ptahschemaapprovals.operator.ptah.run condition met # The namespace the runs work in. Credentials are Secrets; the policy cannot be edited.$ kubectl -n "$NAMESPACE" get secret,configmapNAME TYPE DATA AGEsecret/demo-database Opaque 6 12msecret/demo-mysql-database Opaque 5 12msecret/demo-registry Opaque 4 12msecret/demo-registry-pull kubernetes.io/dockerconfigjson 1 12msecret/demo-shadow-database Opaque 2 12m NAME DATA AGEconfigmap/demo-migration-verification-policy 1 12mconfigmap/demo-verification-policy 1 12mconfigmap/e2e-verification-policy 1 13mconfigmap/kube-root-ca.crt 1 13m # One registry, two addresses. You push to the first; Pods in the cluster pull from the second.$ echo "push to: ${PTAH_OCI_REGISTRY:?is not set}"echo "pull from: ${REGISTRY_IN_CLUSTER:?is not set}"push to: 127.0.0.1:20432pull from: e2e-registry.demo.svc.cluster.local:5000
- Stand up the labLabA four-node kind cluster, the chart from a package, and every image pinned by digest.$ demo/bin/lab versions
- Adopt a database that already has a schemaLifecycleRecord the history a database already earned, and let the operator carry on from there.$ kubectl -n "$NAMESPACE" exec deploy/demo-psql -- psql -c "SELECT * FROM shipments ORDER BY id"
- Start a new database from a checkpointLifecycleA fresh database runs the snapshot and what came after it, and ends up where the long way ends.$ ls demo/migrations-checkpoint
- Apply a schemaLifecyclePublish a schema as an artifact, point the operator at it, and watch it converge.$ cat demo/schemas/v1.sql
- Manage reference dataLifecycleRows declared beside the tables that hold them, reconciled through the same plan.$ cat demo/reference/v1/catalog.go
- Change the schemaLifecycleA second revision, a new digest, and the difference applied as one plan.$ kubectl -n "$NAMESPACE" exec deploy/demo-psql -- psql -c "\dt"
- Ship a second release onto rows that already existLifecycleA backfill that runs against real data, and a history that says it ran once.$ kubectl -n "$NAMESPACE" create configmap shipments-release-1
- Run a prepared migration sequenceLifecycleNumbered SQL files in an artifact, matched against the database's own record of what has run.$ ls demo/migrations
- Refuse a destructive changeSafetyThe third revision drops a column. The policy says no, and says so before anything runs.$ kubectl -n "$NAMESPACE" exec deploy/demo-psql -- psql -c "INSERT INTO customers (id, email) VALUES (1, 'a@example.test') RETURNING id, email"
- Approve a planSafetyWith apply set to OnApproval, nothing runs until a person approves that exact plan.$ cat demo/manifests/manual-approval/storefront.yaml
- Retire a used approvalSafetyAn approval describes one plan against one observed state. Applying it moves that state.$ kubectl ptah schema storefront -n "$NAMESPACE"
- Close the driftOperationsSomeone changes the database by hand. The operator notices and puts it back.$ kubectl ptah schema storefront -n "$NAMESPACE"
- Fail, then recoverOperationsPoint it at a database that is not there. It says so, keeps trying, and converges when it is.$ kubectl -n "$NAMESPACE" create configmap storefront-v1 --from-file=schema.sql=demo/schemas/v1.sql
- Recover a MySQL migration that stopped halfwayOperationsDDL that committed, a run nobody can retry, and a repair decided by what the database holds.$ for release in 1 2 3; do
- Suspend and resumeOperationsOne field stops reconciliation without deleting anything, and resuming picks up where it stopped.$ kubectl ptah schema storefront -n "$NAMESPACE"