operatorBox.emit

3 min read

operatorBox.emit declares outputs the runtime produces on behalf of the operator after each reconcile cycle. It groups two concerns: the status: declaration (moved here from the operatorBox top level) and events:, which declares named Kubernetes events emitted in postReconcile.

Both typed and declarative reconcilers have access to emit: — it is evaluated by the runtime, not the reconciler.

Declaration

spec:
  crds:
    app:
      operatorBox:
        emit:
          status:
            fields:
              - path: phase
                value: "{{ .status.phase }}"

          events:
            DatabaseReady:
              type: Normal
              reason: Ready
              message: "{{ .spec.name }} is ready"
              on: [success]

            DatabaseSyncFailed:
              type: Warning
              reason: SyncFailed
              message: "{{ .spec.name }} failed to sync: {{ .status.lastError }}"
              on: [failure]

emit fields

FieldTypeRequiredDescription
statusStatusConfignoDeclarative status fields written after every reconcile.
eventsmapnoNamed Kubernetes events emitted in postReconcile.

emit.events[] fields

events is a map. The map key is the event name — a stable identifier used for per-event deduplication within a reconcile cycle.

FieldTypeRequiredDescription
typestringyesKubernetes event type. Must be Normal or Warning.
reasonstringyesEvent reason field. Static string.
messagestringyesHuman-readable message. Evaluated as a Go template against the prepared resolver context.
on[]stringnoReconcile outcomes that trigger this event. Valid values: always, success, failure. Defaults to always when omitted.
when[]ConditionnoAND conditions. All must pass for the event to be emitted.
or[]ConditionnoOR conditions. Any passing condition emits the event.

on: gates by reconcile outcome before condition evaluation. Use on: [success] for informational events and on: [failure] for warning events. when:/or: can be combined with on: for finer control — both must pass.

Condition evaluation

when: and or: use the same condition syntax as preReconcile.reconcileGate. The resolver available in postReconcile includes cross, profiles, notes, and the status produced by the completed reconcile cycle — so conditions like field: .status.phase reflect current state.

See When Conditions for the full condition syntax reference.

Pub/sub pairing with observe.events

emit.events is the producer side. observe.events is the consumer side. An event emitted by Operator A can trigger reconciliation in Operator B:

# Operator A — emitting
operatorBox:
  emit:
    events:
      DatabaseSyncFailed:
        type: Warning
        reason: SyncFailed
        message: "{{ .spec.name }} sync failed"
        on: [failure]
# Operator B — consuming
operatorBox:
  observe:
    events:
      dbFailed:
        reason: SyncFailed
        type: Warning
        reportingController: orkestra-runtime

Operator A emits the event. It lands in the Kubernetes event stream. Operator B’s observe.events.dbFailed watch sees a Warning event with reason: SyncFailed from orkestra-runtime and enqueues Operator B’s primary CR. Neither operator knows about the other.

All events emitted via emit.events are attributed to reportingController: orkestra-runtime — set by the runtime’s event recorder.