Skip to content

Neutron Controller Events ​

Reference documentation for the Kubernetes events the two Neutron controllers emit. They make a failed migration Job, a refused release transition and a failed OVN comparison visible through kubectl describe neutron and kubectl get events without reading controller logs.

Events complement status conditions. A condition reports current state for programmatic consumers; an event is a timestamped record of a transition, which is what an operator reads after the fact and what an alerting rule matches on. For the conditions themselves see Neutron CRD and NeutronMetadataAgent CRD; for the pipelines that set them, Reconciler Architecture.


Event Conventions ​

  • Reason strings are stable PascalCase identifiers. They are part of the controllers' public API and will not change without a deprecation notice.
  • Normal marks the successful completion of a lifecycle transition, Warning a failure, a refused transition or a degradation that needs attention.
  • No event is emitted for an in-progress or polling state, so a requeue cycle produces no event noise. DBSyncInProgress, ExpandInProgress and their siblings are condition reasons only.
  • An event on a Neutron (involvedObject.kind: Neutron) carries the recorder name neutron-controller, and one on a NeutronMetadataAgent carries neutronmetadataagent-controller. That is what the reportingComponent field selector matches. Both recorders are wired in operators/neutron/main.go.
  • The API server deduplicates events by (involvedObject, reason, message, source). Repeated identical events increment a counter rather than creating new objects.

Event Reasons Reference ​

Configuration ​

ReasonTypeTrigger ConditionExample Message
ExtraConfigOwnedKeyOverrideWarningspec.extraConfig overrides one or more operator-owned configuration keys of the kind's ownership registryspec.extraConfig overrides operator-owned keys: [ovn] ovn_l3_scheduler

Source: the shared RecordExtraConfigHealth in internal/common/config/ownership.go, called from reconcileConfig in reconcile_config.go for a Neutron and from reconcileAgentConfig in reconcile_agent_config.go for a NeutronMetadataAgent

Note: The event is gated on the ExtraConfigHealthy=False condition's message. It fires once on the transition into False and once more when the overridden-key set changes, never on the steady reconcile poll. Removing the overrides transitions the condition back to ExtraConfigHealthy=True, Reason=NoOwnedKeysOverridden without a further event. The condition is informational and is not aggregated into Ready. The keys the validating webhook refuses at admission (fourteen on Neutron, six on NeutronMetadataAgent) never reach this path.

Database Sync ​

ReasonTypeTrigger ConditionExample Message
DatabaseSyncedNormalThe {name}-db-sync Job completes successfullyDatabase schema is up to date
DBSyncFailedWarningThe {name}-db-sync Job failsdb_sync job failed: <error>
DBSyncMetricEmissionDeferredWarningPatching the last-observed Job UID annotation onto the Neutron fails, deferring the db_sync metrics to the next reconcilePatching last-observed db-expand Job UID failed; metric emission deferred to the next reconcile: <error>

Source: the shared ReconcileSyncJobs in internal/common/database/flow.go (DatabaseSynced / DBSyncFailed); the shared RecordJobTerminalState in internal/common/job/terminal.go, wired through recordDBJobTerminalState in db_job_metrics.go (DBSyncMetricEmissionDeferred)

One deferral reason covers four Jobs. The %s in the message is the phase suffix the metrics are keyed on, so it reads db-sync in steady state and db-expand, db-migrate or db-contract during a release upgrade.

Release Transitions ​

The release gate validates a spec.openStackRelease change against status.installedRelease before the upgrade flow is entered. A refused transition sets DatabaseReady=False, raises one Warning event whose reason names the rule that refused it, and returns an error so the controller backs off.

ReasonTypeTrigger ConditionExample Message
VersionParseErrorWarningThe installed or the requested release is not a valid YYYY.N stringparsing requested release "latest": invalid release format "latest": expected YYYY.N
DowngradeNotSupportedWarningThe requested release is older than the installed onedowngrade from 2026.2 to 2026.1 is not supported
UpgradePathInvalidWarningThe requested jump is more than one releaseupgrade from 2024.2 to 2026.1 is not sequential; upgrade one release at a time
ImageReleaseMismatchWarningThe requested release bump leaves spec.image at the reference that migrated the installed schema, so no migration would runsee the message below

Source: gateReleaseTransition and rejectReleaseTransition in reconcile_database.go

The gate runs ahead of the upgrade flow, so the wording an operator sees for the first three reasons is the gate's. The shared InitiateUpgrade carries the same three reasons with capitalised wording of its own, behind that gate.

ImageReleaseMismatch names both readings of the state it refuses, because only the operator knows which one applies and the recovery differs:

text
upgrade from %s to %s leaves spec.image unchanged (%s), so no migration would run: either bump spec.image in lockstep with spec.openStackRelease, or — if that image already migrated the schema on an earlier pass, because its digest was bumped before spec.openStackRelease was — patch status.installedRelease to %s to record the migration that has already run

Note: ImageReleaseMismatch has a second trigger that raises no event. When a tag-pinned spec.image names a different OpenStack release than spec.openStackRelease, checkImageReleaseMismatch sets DatabaseReady=False with that reason and requeues without recording anything, because the check runs on every pass and would otherwise re-fire for as long as the two fields disagree. Read that case off the condition, not the event stream.

Upgrade ​

An accepted release bump walks the shared expand-migrate-contract flow. Neutron runs the full phase machine: its alembic tree splits into an expand and a contract branch, and status.upgradePhase reports where a bump has got to.

ReasonTypeTrigger ConditionExample Message
UpgradeInitiatedNormalAn accepted release bump starts the upgradeUpgrade initiated: 2026.1 → 2026.2
ExpandCompleteNormalThe {name}-db-expand Job succeededExpand phase complete: 2026.1 → 2026.2
MigrateCompleteNormalThe {name}-db-migrate Job succeededMigrate phase complete: 2026.1 → 2026.2
DeploymentRolloutCompleteNormalThe API Deployment rolled out onto the target-release image; the phase flips to ContractingDeployment rollout complete during upgrade 2026.1 → 2026.2
UpgradeCompleteNormalThe {name}-db-contract Job succeeded; the upgrade finishedUpgrade complete: 2026.1 → 2026.2
UpgradeAbortedNormalspec.openStackRelease reverted to the installed release, cancelling the upgrade and deleting the three phase JobsUpgrade 2026.1 → 2026.2 aborted: spec release reverted to installed release 2026.1
UpgradeTargetChangedWarningspec.openStackRelease changed to a third value during an active upgradeSpec release changed to 2027.1 during active upgrade 2026.1 → 2026.2
ExpandFailedWarningThe expand phase Job failed permanentlyExpand job neutron-db-expand failed: <error>
MigrateFailedWarningThe migrate phase Job failed permanentlyMigrate job neutron-db-migrate failed: <error>
ContractFailedWarningThe contract phase Job failed permanentlyContract job neutron-db-contract failed: <error>
VersionParseError, DowngradeNotSupported, UpgradePathInvalidWarningThe same three rules, re-checked inside InitiateUpgradeDowngrade from 2026.2 to 2026.1 is not supported

Source: the shared expand-migrate-contract flow in internal/common/database/upgrade.go, wired through upgradeFlowParams in reconcile_database.go and CompleteRollingUpdate in reconcile_deployment.go

The migrate phase runs neutron-db-manage current. Neutron's alembic tree has no data-migration command between expand and contract, and printing the revision each branch sits at keeps the phase readable in the Job log.

OVN Schema Sync ​

ReasonTypeTrigger ConditionExample Message
OVNDBSyncJobFailedWarningThe newest terminal run of the {name}-ovn-db-sync CronJob failedsee the template below
OVNDBSyncMetricEmissionDeferredWarningPatching the last-observed Job UID annotation onto the Neutron failed, so the OVN sync metrics are deferred to the next reconcilePatching last-observed ovn-db-sync Job UID failed; metric emission deferred to the next reconcile: <error>

Source: reconcileOVNDBSync in reconcile_ovndbsync.go; the second reason is the deferral reason its RecordJobTerminalState call passes

text
OVN database synchronisation Job %s failed; inspect its pod logs. A "Could not retrieve schema from <address>" line means the Northbound database was unreachable rather than out of step

That line is the one distinction the log carries. log mode exits 0 whether or not the two databases agree, so a non-zero exit is an unreachable Northbound or a broken run, never drift.

OVNDBSyncJobFailed is also the reason of the OVNDBSyncReady=False condition, and the two fire on different schedules. The condition is set on every pass for as long as the failed Job stays the newest terminal one; the event rides the terminal-state helper, which dedupes on the Job UID through an annotation on the CR, so it fires once per failed run.

Finalization ​

Emitted while the finalizers tear a deleted Neutron down. FinalizingDatabase is gated on live MariaDB cleanup work remaining, so brownfield CRs (no MariaDB CRs) and repeated requeue polls produce no noise.

ReasonTypeTrigger ConditionExample Message
FinalizingDatabaseNormalDeletion begins while MariaDB Database/User/Grant CRs are still liveCleaning up MariaDB Database, User, and Grant before removing Neutron
DatabaseFinalizedNormalMariaDB resources marked for deletion; finalizer releasedMariaDB Database, User, and Grant marked for deletion; releasing finalizer
RemoteChildrenAbandonedWarningDeletion begins while the target cluster the CR named no longer resolves; the finalizer is released without touching what was written thereTarget cluster is no longer registered; releasing the finalizer without deleting the MariaDB Database, User, and Grant on it

Source: reconcileDelete in neutron_controller.go

A placed Neutron carries a second finalizer for the children on the target cluster, and its sweep raises RemoteChildrenAbandoned under a message of its own:

text
Target cluster is no longer registered; releasing the remote-children finalizer without deleting the objects on it labelled as owned by this Neutron

Source: SweepRemoteChildren in internal/common/multicluster/teardown.go, called from reconcileDeleteRemoteChildren in both controllers

Before the abandon window expires the deletion requeues instead, and the wait is reported with reason TargetClusterUnavailable on the first condition of the CR's pipeline: SecretsReady=False on a Neutron, ChassisReady=False on a NeutronMetadataAgent. Engagement of a target cluster is asynchronous, so an operator restart looks like a deregistration until the provider has synced.

Metadata Agent Controller ​

neutronmetadataagent-controller records three reasons. The first two are shared with the Neutron controller and listed above:

ReasonTypeTrigger ConditionExample Message
ExtraConfigOwnedKeyOverrideWarningspec.extraConfig overrides one or more keys of MetadataAgentOwnedConfigKeysspec.extraConfig overrides operator-owned keys: [oslo_concurrency] lock_path (the operator mounts a writable volume at this path; another path names a directory the container cannot write)
RemoteChildrenAbandonedWarningA placed agent is deleted while its target cluster no longer resolvesTarget cluster is no longer registered; releasing the remote-children finalizer without deleting the objects on it labelled as owned by this NeutronMetadataAgent
MetadataSharedSecretMirrorReapedNormalA placed agent is deleted and no other live agent in its namespace on its cluster names a metadata shared-secret copy the ControlPlane delivered there. One event per deleted copyDeleted the metadata shared-secret mirror controlplane-nova-metadata-agent-secret: no other NeutronMetadataAgent on this cluster names it

Nothing else in that pipeline raises an event. The chassis, the credentials and the DaemonSet all report through their conditions, since each of their states is one to wait out and retry; none of them is a transition worth an audit record.

Reasons that never fire for Neutron ​

ReasonWhy it cannot occur
SchemaDriftDetectedThe Job set carries no schema-check command (SchemaCheckCommand: nil). neutron-db-manage upgrade head applies every pending revision of both branches in one idempotent pass, so a second read-only Job would assert nothing
DBSyncInProgress, ExpandInProgress, MigrateInProgress, ContractInProgress, UpgradeRollingUpdateDatabaseReady=False condition reasons while a Job or a rollout runs, never events: the polling states raise none
Every reason of ChassisReady, OVNEndpointsReady, DeploymentReady, WorkersReady, NeutronAPIReady, HTTPRouteReady, HPAReady and NetworkPolicyReadyThese steps report on their conditions alone. Read the current state there

Alerting Configuration ​

Event reason strings are designed to be stable identifiers for alerting rules. Use kubectl get events --field-selector to filter by reason:

bash
# Watch for db-sync failures
kubectl get events --field-selector reason=DBSyncFailed -w

# Watch for a rejected release upgrade path
kubectl get events --field-selector reason=UpgradePathInvalid -w

# Watch for a failed comparison against the OVN Northbound database
kubectl get events --field-selector reason=OVNDBSyncJobFailed -w

# Watch for an extraConfig override of an operator-owned key
kubectl get events --field-selector reason=ExtraConfigOwnedKeyOverride -w

# Watch for children left behind on a deregistered target cluster
kubectl get events --field-selector reason=RemoteChildrenAbandoned -w

# Watch for all Warning events from either controller
kubectl get events --field-selector type=Warning,reportingComponent=neutron-controller -w
kubectl get events --field-selector type=Warning,reportingComponent=neutronmetadataagent-controller -w

Prometheus Alertmanager Example ​

When using kube-state-metrics with event metrics enabled, you can alert on specific event reasons:

yaml
groups:
  - name: neutron-events
    rules:
      - alert: NeutronDBSyncFailed
        expr: |
          increase(kube_event_count{
            reason="DBSyncFailed",
            involved_object_kind="Neutron"
          }[5m]) > 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "Neutron db-sync failed"
          description: "The Neutron db-sync Job has failed. Check the Job logs for details."

A failed OVN comparison also moves neutron_operator_ovn_db_sync_total{result="failed"}, which is the signal to alert on where the event stream is not collected.


Event Flow ​

The event flow of the Neutron operator: the two reconcilers, the sub-reconcilers that emit events, and for each the condition and the event it emits. NeutronReconciler.Reconcile(): reconcileDelete() (deletionTimestamp set) emits Normal FinalizingDatabase when MariaDB CRs still live; Normal DatabaseFinalized when MariaDB cleanup done; Warning RemoteChildrenAbandoned when target cluster unresolvable; reconcileConfig() emits Warning ExtraConfigOwnedKeyOverride when spec.extraConfig overrides operator-owned keys (gated on transition into ExtraConfigHealthy=False, Reason=OwnedKeysOverridden); reconcileDatabase() emits nothing when tag/release mismatch (condition only); Warning VersionParseError or DowngradeNotSupported or UpgradePathInvalid or ImageReleaseMismatch when release gate refuses; Normal UpgradeInitiated when upgrade accepted; Normal ExpandComplete or MigrateComplete or UpgradeComplete when expand / migrate / contract Job succeeded; Warning ExpandFailed or MigrateFailed or ContractFailed when phase Job failed; Warning UpgradeTargetChanged when spec release moved; Normal UpgradeAborted when spec release reverted; Warning DBSyncFailed when db_sync fails; Normal DatabaseSynced when db_sync succeeds; Warning DBSyncMetricEmissionDeferred when Job-UID patch fails; reconcileDeployment() emits Normal DeploymentRolloutComplete when rollout done in the RollingUpdate phase; reconcileOVNDBSync() emits Warning OVNDBSyncJobFailed when newest terminal sync Job failed; Warning OVNDBSyncMetricEmissionDeferred when Job-UID patch failed; NeutronMetadataAgentReconciler.Reconcile(): deletion, target cluster unresolvable past the abandon window emits Warning RemoteChildrenAbandoned (finalizer released, children left behind); deletion of a placed agent, reapMetadataSharedSecretMirrors() emits Normal MetadataSharedSecretMirrorReaped when labelled copy no other agent there names; reconcileAgentConfig() emits Warning ExtraConfigOwnedKeyOverride when spec.extraConfig overrides operator-owned keys;

The figure draws which sub-reconciler emits which event, and on what. The Event Reasons Reference describes every reason.