LynqNode API Reference
Kind: LynqNode
API Version: operator.lynq.sh/v1
Group: operator.lynq.sh
LynqNode represents one active database row × one LynqForm combination. Created and deleted automatically by the LynqHub controller — users typically don't create or edit LynqNodes directly.
→ Resource lifecycle guide · API index
Spec
LynqNode specs are generated by the hub controller and mirror the LynqForm structure with template variables resolved into the metadata.annotations. Direct editing is unusual.
apiVersion: operator.lynq.sh/v1
kind: LynqNode
metadata:
name: acme-corp-web-app # format: {uid}-{form-name}
namespace: lynq-system
annotations:
lynq.sh/uid: "acme-corp" # resolved .uid variable
lynq.sh/activate: "true" # resolved .activate variable
lynq.sh/planId: "enterprise" # from extraValueMappings
lynq.sh/nodeUrl: "https://..." # from extraValueMappings
labels:
lynq.sh/hub: production-nodes # source hub
lynq.sh/uid: acme-corp
spec:
uid: string # Node unique identifier
templateRef: string # LynqForm name that generated this node
# Rendered resource arrays — same structure as LynqForm
deployments: []
services: []
# ... (all resource types)Status
status:
observedGeneration: int64
desiredResources: int32 # Total resources in the form
readyResources: int32 # Resources with ready condition met
failedResources: int32 # Resources that failed to apply or timed out
skippedResources: int32 # Resources skipped due to dependency failures
skippedResourceIds: []string # IDs of skipped resources
appliedResources: []string # Current set of tracked resources
# Format: "Kind/namespace/name@id"
# Example: "Deployment/default/acme-app@app"
lastFullReconcileAt: timestamp # Baseline used to schedule the next
# periodic force-reapply (drift correction).
# See "lastFullReconcileAt" below.
conditions:
- type: Ready
status: "True" | "False" | "Unknown"
reason: string
message: string
lastTransitionTime: timestamp
- type: Progressing
status: "True" | "False"
reason: string
- type: Degraded
status: "True" | "False"
reason: string
message: string
- type: Conflicted
status: "True" | "False"
reason: stringConditions
Ready
True when all desired resources are applied and ready.
| Reason | Status | Meaning |
|---|---|---|
Reconciled | True | All resources ready |
ResourcesFailedAndConflicted | False | Both failed and conflicted resources exist |
ResourcesConflicted | False | One or more resources in ownership conflict |
ResourcesFailed | False | One or more resources failed to apply |
NotAllResourcesReady | False | Resources exist but haven't reached ready state |
Degraded
True when the node has health issues — even if reconciliation has completed.
| Reason | Status | Meaning |
|---|---|---|
Healthy | False | No issues |
ResourceFailuresAndConflicts | True | Both failed and conflicted resources |
ResourceFailures | True | Failed resources |
ResourceConflicts | True | Conflicted resources |
ResourcesNotReady | True | Resources not yet ready (added v1.1.4) |
Progressing
True during active reconciliation.
Conflicted
True when any resource has an SSA field-manager conflict.
appliedResources
Tracks every resource currently under management. Format: Kind/namespace/name@id.
["Deployment/default/acme-app@app", "Service/default/acme-svc@svc"]Lynq compares this list against the current template on each reconcile. Resources in appliedResources but not in the current template are treated as orphans and handled per their stored deletionPolicy annotation.
lastFullReconcileAt
Timestamp the controller uses to schedule the next periodic force-reapply (drift correction). When time.Since(lastFullReconcileAt) >= ForceReapplyInterval (default 10 minutes), the next reconcile bypasses the per-resource skip check and re-applies every child resource unconditionally. This is the backstop for external mutations that preserve lynq.sh/applied-hash on a child resource and would therefore not be caught by the annotation-only skip path.
A nil value (absent field) means the controller has not yet established a baseline for this node — either the LynqNode is brand-new or the controller just restarted and observed it for the first time. The controller treats nil as "stamp now as the baseline and defer the first force by one full interval". This deferral prevents a re-apply storm across all LynqNodes on every controller restart.
The companion annotations on child resources are:
lynq.sh/applied-hash— desired-spec hash from the last successful apply. The skip check compares this against the freshly computed hash; equal ⇒ skip.lynq.sh/apply-start-time— wall-clock timestamp stamped at the most recent apply (preserved across reconciles when the spec is unchanged). Used as the readiness-timeout reference instead ofcreationTimestamp.
Both annotations are written atomically as part of the SSA / Update payload — no follow-up MergePatch — so the skip check never observes a half-stamped state.
Lifecycle
Creation
LynqHub creates a LynqNode for each activeRow × referencingForm combination. The LynqNode controller then:
- Adds finalizer
lynqnode.operator.lynq.sh/finalizer - Renders templates with variables from
metadata.annotations - Builds dependency graph from
dependIds - Applies resources in topological order
- Waits for readiness (per
waitForReady/timeoutSeconds) - Updates status
Deletion
When the LynqNode is deleted, the finalizer runs cleanup:
- Resources with
deletionPolicy: Delete— removed from cluster - Resources with
deletionPolicy: Retain— orphan markers added, resource stays
After cleanup, the finalizer is removed and Kubernetes deletes the CR.
Periodic reconciliation
The LynqNode controller requeues every 30 seconds to detect child resource status changes (e.g., a Deployment becoming ready). Combined with event-driven watches on 12 resource types, status reflects reality within ~30 seconds.
kubectl Reference
# List all nodes with status
kubectl get lynqnodes -n lynq-system
# Check ready/desired ratio
kubectl get lynqnode <name> -o jsonpath='{.status.readyResources}/{.status.desiredResources}'
# View all conditions
kubectl get lynqnode <name> -o jsonpath='{range .status.conditions[*]}{.type}: {.status} ({.reason}){"\n"}{end}'
# Find resources managed by this node
kubectl get all -l lynq.sh/node=<name>
# Find skipped resources (dependency failures)
kubectl get lynqnode <name> -o jsonpath='{.status.skippedResourceIds}'
# Force reconciliation
kubectl annotate lynqnode <name> lynq.sh/force-reconcile=$(date +%s) --overwrite
# Watch ready count
watch kubectl get lynqnode <name> -o jsonpath='{.status.readyResources}/{.status.desiredResources}'See Also
- Resource Lifecycle — tracking labels, orphan markers, re-adoption, cross-namespace
- Troubleshooting — diagnosing degraded or stuck nodes
- LynqHub API — source hub configuration
- LynqForm API — resource blueprint
- API index — common types and shared kubectl reference
