PtahSchemaPlan
PtahSchemaPlan is a namespaced resource in operator.ptah.run, served as v1alpha1.
This page is generated from the API types by make docs-reference. The shipped CRDs carry no descriptions, so this is where the field documentation lives.
Examples
Section titled “Examples”Nobody writes a PtahSchemaPlan. The operator publishes one when it has
compared the declaration against the database, and the object is immutable
afterwards: it is the thing an approval names and the thing Apply reconstructs
and rehashes before it runs anything.
The examples below are what kubectl get -o yaml returns, shortened to the
fields worth looking at. Read the SQL with the plugin rather than out of the
object – the statements are stored in PtahSchemaPlanChunk objects, and the
plugin assembles and checks them:
kubectl ptah plan application -n applicationA plan with changes in it
Section titled “A plan with changes in it”destructive and privilegeChanges are the fields to read first.
destructive: false says no statement in this plan drops or rewrites anything,
and a plan with no privilegeChanges grants, revokes and delegates nothing.
spec.fingerprint is what an approval must name, and it binds far more than
the SQL – the artifact, the observed and desired state, the policy, the target
identity and every executing image.
apiVersion: operator.ptah.run/v1alpha1kind: PtahSchemaPlanmetadata: name: ptah-plan-71c480df93d6ae2f14efe3c4 namespace: application # The plan belongs to the schema and is collected with it. ownerReferences: - apiVersion: operator.ptah.run/v1alpha1 kind: PtahSchema name: application uid: 4f2c9e1a-5b6d-4a7e-9c31-0d8f2b6a4e57 controller: truespec: schemaRef: name: application uid: 4f2c9e1a-5b6d-4a7e-9c31-0d8f2b6a4e57 fingerprint: sha256:71c480df93d6ae2f14efe3c44baabb7d3bc5d0e2de07d0e7a9b1a6cbd5f7ca3f dialect: postgres destructive: false statementCount: 4 size: 1832 contentDigest: sha256:3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea # The SQL itself, in PtahSchemaPlanChunk objects this plan owns. A plan is # bounded: at most 16 chunks of 512 KiB, and 8 MiB in total. chunks: - index: 0 name: ptah-plan-71c480df93d6ae2f14efe3c4-000 size: 1832 digest: sha256:3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea contractVersion: 1 artifactDigest: sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae verificationPolicyUID: 7c9e6679-7425-40de-944b-e07fc1f90ae7 verificationPolicyDigest: sha256:084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff29c5 desiredStateFingerprint: sha256:19581e27de7ced00ff1ce50b2047e7a567c76b1cbaebabe5ef03f7c3017bb5b7 actualStateFingerprint: sha256:4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5 coordinationDigest: sha256:e7f6c011776e8db7cd330b54174fd76f7d0216b612387a5ffcfb81e6f0919683 targetIdentityDigest: sha256:67586e98fad27da0b9968bc039a1ef34c939b9b8e523a8bef89d478608c5ecf6 policyFingerprint: sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9 ptahVersion: v0.15.0 executorImage: ghcr.io/stokaro/ptah@sha256:1b4f0e9851971998e732078544c96b36c3d01cedf7caa332359d6f1d83567014 runnerProtocolVersion: 1 executionBindingID: v1-9f8e7d6c5b4a39281706f5e4d3c2b1a0 controllerStateVersion: 1 # The manager that published the plan. Recorded, not bound: none of the # three is in the fingerprint, and a later release of the manager applies # this plan as it stands. controllerImage: ghcr.io/stokaro/ptah-operator@sha256:fd61a03af4f77d870fc21e05e7e80678095c92d808cfb3b5c279ee04c74aca13 controllerRevision: a7d0119c0bd0d34e0b73f1d9e0e5c6aa0d9ff2b1 runnerImage: ghcr.io/stokaro/ptah-runner@sha256:60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752A plan that would destroy something
Section titled “A plan that would destroy something”Same shape, destructive: true. With spec.policy.allowDestructive left at
its default, the schema does not offer this plan for approval at all: it stays
Blocked, and an approval naming it is refused. Reading the plan is how you
find out what the artifact would have dropped.
apiVersion: operator.ptah.run/v1alpha1kind: PtahSchemaPlanmetadata: name: ptah-plan-9c56cc51b374c3ba189210d5 namespace: applicationspec: schemaRef: name: application uid: 4f2c9e1a-5b6d-4a7e-9c31-0d8f2b6a4e57 fingerprint: sha256:9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab dialect: postgres destructive: true statementCount: 1 size: 396 contentDigest: sha256:0c3a2a729409b8995b48a2faf12ab1482177cbf660ea2655729c3ab825be67de chunks: - index: 0 name: ptah-plan-9c56cc51b374c3ba189210d5-000 size: 396 digest: sha256:0c3a2a729409b8995b48a2faf12ab1482177cbf660ea2655729c3ab825be67de contractVersion: 1 artifactDigest: sha256:d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35 verificationPolicyUID: 7c9e6679-7425-40de-944b-e07fc1f90ae7 verificationPolicyDigest: sha256:084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff29c5 desiredStateFingerprint: sha256:4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce actualStateFingerprint: sha256:4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5 coordinationDigest: sha256:e7f6c011776e8db7cd330b54174fd76f7d0216b612387a5ffcfb81e6f0919683 targetIdentityDigest: sha256:67586e98fad27da0b9968bc039a1ef34c939b9b8e523a8bef89d478608c5ecf6 policyFingerprint: sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9 ptahVersion: v0.15.0 executorImage: ghcr.io/stokaro/ptah@sha256:1b4f0e9851971998e732078544c96b36c3d01cedf7caa332359d6f1d83567014 runnerImage: ghcr.io/stokaro/ptah-runner@sha256:60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752 runnerProtocolVersion: 1 executionBindingID: v1-9f8e7d6c5b4a39281706f5e4d3c2b1a0 controllerImage: ghcr.io/stokaro/ptah-operator@sha256:fd61a03af4f77d870fc21e05e7e80678095c92d808cfb3b5c279ee04c74aca13 controllerRevision: a7d0119c0bd0d34e0b73f1d9e0e5c6aa0d9ff2b1 controllerStateVersion: 1A plan that changes privileges
Section titled “A plan that changes privileges”Ptah rates a grant, a new role or a SECURITY DEFINER function safe, and
none of them loses data, so destructive stays false. The operator reads the
statements itself and lists what kinds of authority they change. Any entry in
privilegeChanges means the plan waits for an approval even when the schema
says apply: Always, and the schema’s ApprovalRequired condition says so with
reason PrivilegeChanges. The list names kinds only; which table was granted to
whom is in the SQL.
apiVersion: operator.ptah.run/v1alpha1kind: PtahSchemaPlanmetadata: name: ptah-plan-3263a9026c3e3f7e368860bd namespace: applicationspec: schemaRef: name: application uid: 4f2c9e1a-5b6d-4a7e-9c31-0d8f2b6a4e57 fingerprint: sha256:3263a9026c3e3f7e368860bd0443650cad3680f3e1232433fee3766613a67167 dialect: postgres destructive: false # A GRANT, and a function Ptah writes as CREATE OR REPLACE with # SECURITY DEFINER. privilegeChanges: - Grant - SecurityDefiner - FunctionReplacement statementCount: 2 size: 653 contentDigest: sha256:e93552f381cd8ee8958d6c097b84b4fc868e8ccacb028fd1acfc54725692a12e chunks: - index: 0 name: ptah-plan-3263a9026c3e3f7e368860bd-000 size: 653 digest: sha256:e93552f381cd8ee8958d6c097b84b4fc868e8ccacb028fd1acfc54725692a12e contractVersion: 1 artifactDigest: sha256:ef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d verificationPolicyUID: 7c9e6679-7425-40de-944b-e07fc1f90ae7 verificationPolicyDigest: sha256:084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff29c5 desiredStateFingerprint: sha256:e9dd8cf61b2be0e276c9e16e0a147dc02df8c4b06835721ca43adc99cbfa06a3 actualStateFingerprint: sha256:4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5 coordinationDigest: sha256:e7f6c011776e8db7cd330b54174fd76f7d0216b612387a5ffcfb81e6f0919683 targetIdentityDigest: sha256:67586e98fad27da0b9968bc039a1ef34c939b9b8e523a8bef89d478608c5ecf6 policyFingerprint: sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9 ptahVersion: v0.15.0 executorImage: ghcr.io/stokaro/ptah@sha256:1b4f0e9851971998e732078544c96b36c3d01cedf7caa332359d6f1d83567014 runnerImage: ghcr.io/stokaro/ptah-runner@sha256:60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752 runnerProtocolVersion: 1 controllerImage: ghcr.io/stokaro/ptah-operator@sha256:fd61a03af4f77d870fc21e05e7e80678095c92d808cfb3b5c279ee04c74aca13 controllerStateVersion: 1| Field | Type | What it does |
|---|---|---|
spec.actualStateFingerprint |
string, required |
ActualStateFingerprint is the observed database state the plan was computed from. Drift since then retires the plan rather than applying it. |
spec.artifactDigest |
string |
This resource requires: contract version 1 binds artifactDigest and a verification policy; contract version 2 binds source. ArtifactDigest is the OCI artifact this plan was computed from, pinned to content rather than to the tag it was resolved through. |
spec.chunks |
[]object, required |
Chunks are the PtahSchemaPlanChunk objects the plan bytes are stored in. The plan is the concatenation of their data in index order, and nothing reads them without checking each digest and size. |
spec.chunks[].digest |
string, required |
Digest of this chunk’s bytes, checked when the plan is read back. |
spec.chunks[].index |
integer, required |
Index of this chunk in the plan, counting from zero. The chunks are concatenated in this order and in no other. |
spec.chunks[].name |
string, required |
Name of the PtahSchemaPlanChunk holding this chunk. An Apply projects the chunk into its Pod through an immutable ConfigMap of the same name. |
spec.chunks[].size |
integer, required |
Size of this chunk in bytes, checked with the digest. |
spec.contentDigest |
string, required |
ContentDigest is the digest of the plan bytes the chunks reconstruct. |
spec.contractVersion |
integer, required, one of 1, 2 |
This resource requires: contract version 1 binds artifactDigest and a verification policy; contract version 2 binds source. ContractVersion versions plan publication and reconstruction separately from the Kubernetes API version. Version 1 is a plan computed from an OCI artifact, and binds artifactDigest and the verification policy. Version 2 is a plan computed from a ConfigMap or a Git commit, and binds source instead. A manager that knows only version 1 refuses a version 2 plan. |
spec.controllerImage |
string, required |
ControllerImage is the digest-pinned manager that published this plan. It is a record, not a binding: the fingerprint leaves it out, and a later manager may apply the plan. |
spec.controllerRevision |
string, required |
ControllerRevision is that manager’s revision, recorded the same way. |
spec.controllerStateVersion |
integer, required |
ControllerStateVersion is the state semantics that manager writes, so a plan is never applied by a controller that reads status differently. |
spec.coordinationDigest |
string, required |
CoordinationDigest is the database realm this plan takes its turn in: the engine and the coordination key, hashed. Resources that share it never run against the database at the same time. |
spec.desiredStateFingerprint |
string, required |
DesiredStateFingerprint is the state the verified artifact declared when the plan was computed. |
spec.destructive |
boolean, required |
Destructive says the plan drops or rewrites something. Such a plan needs spec.policy.allowDestructive and an approval naming these exact bytes. |
spec.dialect |
string, required |
Dialect is the SQL dialect the statements are written in. |
spec.executionBindingID |
string, required |
ExecutionBindingID is the execution epoch the plan was computed under. It changes whenever a component that decides what the plan means when it runs changes – the controller-state version, the Ptah version, the executor image or the runner protocol – even when a rollout returns to byte-identical versions. A manager upgrade that changes none of them keeps it, and the plan stays applicable. |
spec.executorImage |
string, required |
ExecutorImage is the digest-pinned image that ran Ptah. |
spec.fingerprint |
string, required |
Fingerprint is the complete approval identity of this plan: every binding below hashed together. An approval names this value, and an apply runs only while the live bindings still produce it. |
spec.policyFingerprint |
string, required |
PolicyFingerprint is the spec.policy the plan was computed under. Editing the policy – a protected table included – retires a plan waiting for a person rather than letting it apply under rules nobody approved. |
spec.privilegeChanges |
[]string |
PrivilegeChanges names the kinds of authority the plan’s statements change: privileges granted or revoked, role membership, roles, owners, row-security policies and definer rights. A plan that lists any needs an approval naming these exact bytes whatever spec.policy.apply says, so apply: Always does not grant access on its own. The operator reads the kinds from the SQL itself, independently of the severity Ptah gave each statement, and only ever adds to a plan’s class. It names kinds and nothing else: no object, no role and no text. Read the statements with kubectl ptah plan. |
spec.ptahVersion |
string, required |
PtahVersion is the Ptah build that computed this plan, as the executor image reports it. |
spec.runnerImage |
string, required |
RunnerImage is the digest-pinned runner image of the manager that published this plan. Like the manager’s own identity it is recorded and not bound: the runner is built from the operator’s source, and what it enforces is versioned by RunnerProtocolVersion. |
spec.runnerProtocolVersion |
integer, required |
RunnerProtocolVersion is the runner protocol the plan binds: what the runner enforces inside the Pod and the result frame it returns. A runner answering in another version has its result rejected rather than interpreted. |
spec.schemaRef |
object, required |
SchemaRef is the PtahSchema this plan was computed for. |
spec.schemaRef.name |
string, required |
Name of the referenced object in the same namespace. |
spec.schemaRef.uid |
string, required |
UID the object had when the reference was written. An object deleted and recreated under the same name is a different object, and this says so. |
spec.size |
integer, required |
Size is the length of those bytes, summed across the chunks. |
spec.source |
object |
This resource requires: contract version 1 binds artifactDigest and a verification policy; contract version 2 binds source. Source is the ConfigMap source this plan was computed from: the ConfigMap’s UID and the content digest of the selected files. |
spec.source.contentDigest |
string, required |
ContentDigest is the content digest of the files the plan was computed from. |
spec.source.kind |
string, required, one of ConfigMap, Git |
Kind of source the plan was computed from. |
spec.source.policy |
object |
Policy is the source policy the source was checked against, when the resource names one. |
spec.source.policy.digest |
string, required |
Digest is “sha256:” and the SHA-256 of the policy document. |
spec.source.policy.uid |
string, required |
UID of the policy ConfigMap. Another ConfigMap under the same name is another policy. |
spec.source.revision |
string, required |
Revision is the source object the files were read from. For a ConfigMap it is the ConfigMap’s UID: an edit to a key the source does not select keeps the plan, while another ConfigMap, or the same name deleted and created again, retires it even when the files match. For Git it is “sha256:” and the SHA-256 of the repository URL and the selected path, joined by a newline: another repository or another path retires the plan even when the files match, while a commit that leaves the selected files as they were keeps it, as an edit to an unselected key keeps a ConfigMap’s. |
spec.statementCount |
integer, required |
StatementCount is how many statements the plan holds. Read them with kubectl ptah plan rather than by fetching the chunks. |
spec.targetIdentityDigest |
string, required |
TargetIdentityDigest identifies the database this plan was computed against without carrying anything that could reach it. |
spec.verificationPolicyDigest |
string |
This resource requires: contract version 1 binds artifactDigest and a verification policy; contract version 2 binds source. VerificationPolicyDigest is that policy’s content, so replacing the object or editing it in place both retire the plan. |
spec.verificationPolicyUID |
string |
This resource requires: contract version 1 binds artifactDigest and a verification policy; contract version 2 binds source. VerificationPolicyUID is the policy object that accepted the artifact. |
status
Section titled “status”| Field | Type | What it does |
|---|---|---|
status.conditions |
[]object |
Conditions carry Ready, which is what approval and apply require. |
status.conditions[].lastTransitionTime |
string, required |
lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. |
status.conditions[].message |
string, required |
message is a human readable message indicating details about the transition. This may be an empty string. |
status.conditions[].observedGeneration |
integer |
observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. |
status.conditions[].reason |
string, required |
reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. |
status.conditions[].status |
string, required, one of True, False, Unknown |
status of the condition, one of True, False, Unknown. |
status.conditions[].type |
string, required |
type of condition in CamelCase or in foo.example.com/CamelCase. |
status.observedGeneration |
integer |
ObservedGeneration is the plan generation this status was written for. |
status.publishedChunks |
[]object |
PublishedChunks are the PtahSchemaPlanChunk objects that were found to exist, by UID, before Ready became true. Chunk publication is not transactional, so this is the record that every chunk the manifest names was really written. |
status.publishedChunks[].index |
integer, required |
Index of the chunk this record is for. |
status.publishedChunks[].name |
string, required |
Name of the PtahSchemaPlanChunk that was verified. |
status.publishedChunks[].uid |
string, required |
UID it had when it was verified, so a chunk deleted and recreated is not mistaken for the one the plan was published with. |